﻿//Copyright (c) 2010 Christopher E. S. King (http://chriskingconsulting.com)
//
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml.Linq;
using System.IO;
using System.Threading;
using System.Text.RegularExpressions;
using System.Data.Linq.Mapping;
using System.Data.Linq;
using System.Linq.Expressions;

using King.Extensions;
using King.Reflection;
using King.Infoset.Reflection;
using King.Infoset.Schema;

namespace King.Infoset {

    public sealed class TypedObject {

        #region Static Public Members
        public static TypedObject Make(object target, XsContract contract) {
            if (target == null)
                return null;

            return new TypedObject(target, contract);
        }
        #endregion

        #region Private Data Members
        private object m_target;
        private XsContract m_contract;
        #endregion

        #region Constructor
        private TypedObject(object target, XsContract contract) {
            m_contract = contract;
            m_target = target;
        }
        #endregion

        #region Public Members
        public object Object { get { return m_target; } }
        public XsContract Contract { get { return m_contract; } }
        #endregion
    }
    public static class Extensions {
        public static IEnumerable<XsMember> FlattenGroups(this IEnumerable<XsMember> members) {
            var flattenedMembers =
               (from member in members
                let memberContract = member.Contract
                from o in memberContract.IsGroup ? memberContract.Members().FlattenGroups() : new[] { member }
                select o).ToArray();

            return flattenedMembers;
        }
    }

    #region Loader                          (Loader, Assembly, Schema, Namespace)
    public delegate void OnContractLoadDelegate(XsContract contract);
    public delegate void OnAssemblyLoadDelegate(XsAssembly assembly);
    public sealed class XsNamespace {

        #region Private Data Members
        private XsAssembly m_assembly;
        private XNamespace m_namespace;
        private string m_prefix;
        #endregion

        #region Constructor
        internal XsNamespace(XsAssembly assembly, XsNamespaceAttribute attribute) {

            m_assembly = assembly;
            m_prefix = attribute.Prefix;
            m_namespace = attribute.Namespace;
        }
        #endregion

        #region Public Members
        public XsAssembly Assembly { get { return m_assembly; } }
        public XNamespace Namespace { get { return m_namespace; } }
        public string Prefix { get { return m_prefix; } }
        #endregion

        #region Object Overrides
        public sealed override string ToString() {
            return m_namespace.ToString();
        }
        #endregion
    }
    public sealed class XsSchema {

        #region Definitions
        private static class XsSchemaCache {

            #region Static Private Data Members
            private static Dictionary<XNamespace, XsSchema> s_schemas;
            #endregion

            #region Static Private Members
            private static void Load(XsAssembly xsAssembly) {

                if (xsAssembly.ContractSchema != null)
                    s_schemas.Add(xsAssembly.ContractSchema.Namespace, xsAssembly.ContractSchema);
                if (xsAssembly.AttributeSchema != null)
                    s_schemas.Add(xsAssembly.AttributeSchema.Namespace, xsAssembly.AttributeSchema);
            }
            #endregion

            #region Static Internal Members
            internal static void Initialize() {
                s_schemas = new Dictionary<XNamespace, XsSchema>();
                XsAssembly.OnAssemblyLoad += Load;
            }
            internal static IEnumerable<XsSchema> Schemas() {
                return s_schemas.Values;
            }
            internal static XsSchema GetSchemaOrNull(XNamespace @namespace) {
                return s_schemas.GetValueOrDefault(@namespace);
            }
            internal static XsSchema GetSchema(XNamespace @namespace) {
                var result = GetSchemaOrNull(@namespace);

                if (result == null)
                    throw new ArgumentException();

                return result;
            }
            #endregion
        }
        #endregion

        #region Static Public Members
        public static IEnumerable<XsSchema> Schemas() {
            return XsSchemaCache.Schemas();
        }
        public static XsSchema GetSchema(XNamespace @namespace) {
            var result = GetSchemaOrNull(@namespace);

            if (result == null)
                throw new ArgumentException();

            return result;
        }
        public static XsSchema GetSchemaOrNull(XNamespace @namespace) {
            var result = XsSchemaCache.GetSchemaOrNull(@namespace);
            return result;
        }
        #endregion

        #region Static Constructor
        internal static void Initialize() {
            XsSchemaCache.Initialize();
        }
        #endregion

        #region Private Data Members
        private XNamespace m_namespace;
        private bool m_preserveCase;
        private bool m_isContractTarget;
        private Dictionary<string, Type> m_typesByName;
        private List<XsAssembly> m_assemblies;
        #endregion

        #region Constructor
        internal XsSchema(XsSchemaAttribute attribute) {

            m_namespace = attribute.Namespace;
            m_preserveCase = attribute.PreserveCaseing;
            m_isContractTarget = attribute is XsContractSchemaAttribute;
            m_typesByName = new Dictionary<string, Type>();
            m_assemblies = new List<XsAssembly>();
        }
        internal void Initialize(XsAssembly assembly, IEnumerable<Type> types) {
            if (types.None())
                return;
            m_assemblies.Add(assembly);
            m_typesByName.AddRange(types, o => GetName(o), o => o);
        }
        #endregion

        #region Internal Members
        internal string GetName(Type type) {
            var attribute = type.GetAttribute<XsObjectAttribute>();
            if (attribute == null)
                throw new ArgumentException();
            if (attribute.Name != null)
                return attribute.Name;

            return type.Name;
        }
        internal string GetSchemaName(Type type) {
            var attribute = type.GetAttribute<XsObjectAttribute>();
            if (attribute == null)
                throw new ArgumentException();
            if (attribute.SchemaName != null)
                return attribute.SchemaName;

            if (PreserveCase)
                return GetName(type);

            return GetName(type).ToLowerFirst();
        }
        internal XName GetFullName(Type type) {
            var attribute = type.GetAttribute<XsObjectAttribute>();
            if (attribute == null)
                throw new ArgumentException();
            
            var schemaName = GetSchemaName(type);
            var result = Namespace + schemaName;
            return result;
        }
        #endregion

        #region Public Members
        public XNamespace Namespace { get { return m_namespace; } }
        public bool PreserveCase { get { return m_preserveCase; } }
        public bool IsContractSchema { get { return m_isContractTarget; } }
        public bool IsAttributeSchema { get { return !m_isContractTarget; } }

        public IEnumerable<XsAssembly> Assemblies() {
            return m_assemblies;
        }

        public IEnumerable<XsContract> Contracts() {
            return m_typesByName.Values.Select(o => XsLoader.GetContract(o)).WhereNotNull();
        }
        public XsContract GetContractOrNull(string name) {
            return XsLoader.GetContractOrNull(m_typesByName.GetValueOrDefault(name));
        }
        public XsContract GetContract(string name) {
            var result = GetContractOrNull(name);
            if (result == null)
                throw new ArgumentException();
            return result;
        }
        #endregion

        #region Object Overrides
        public sealed override string ToString() {
            return m_namespace.ToString();
        }
        #endregion
    }
    public sealed class XsAssembly {

        #region Definitions
        private static class XsAssemblyCache {

            #region Static Private Data Members
            private static Dictionary<Assembly, XsAssembly> s_assemblies;
            #endregion

            #region Static Private Members
            private static void Load(Assembly assembly) {

                var xsAssembly = new XsAssembly(assembly);
                s_assemblies.Add(assembly, xsAssembly);

                if (OnAssemblyLoad != null)
                    OnAssemblyLoad(xsAssembly);
            }
            #endregion

            #region Static Internal Members
            internal static void Initialize() {
                XsSchema.Initialize();

                // TODO: Fix race
                s_assemblies = new Dictionary<Assembly, XsAssembly>();

                Load(System.Reflection.Assembly.GetExecutingAssembly());

                var domain = AppDomain.CurrentDomain;
                var thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();

                // raise OnAssemblyLoad for assemblies loaded in the future
                domain.AssemblyLoad +=
                    delegate(object sender, AssemblyLoadEventArgs args) {
                        var assembly = args.LoadedAssembly;
                        if (assembly.References(thisAssembly))
                            Load(assembly);
                    };

                // raise OnAssemblyLoad for loaded assemblies
                foreach (var assembly in domain.GetAssemblies().Where(o => o.References(thisAssembly)))
                    Load(assembly);
            }
            internal static IEnumerable<XsAssembly> Assemblies() {
                return s_assemblies.Values;
            }
            internal static XsAssembly GetAssemblyOrNull(Assembly assembly) {
                if (s_assemblies == null)
                    Assemblies();

                return s_assemblies.GetValueOrDefault(assembly);
            }
            internal static XsAssembly GetAssembly(Assembly assembly) {
                var result = GetAssemblyOrNull(assembly);

                if (result == null)
                    throw new ArgumentException();

                return result;
            }
            #endregion

            #region Static Internal Events
            internal static event OnAssemblyLoadDelegate OnAssemblyLoad;
            #endregion
        }
        private class XsContractCache {

            #region Private Data Members
            private XsAssembly m_assembly;
            private Dictionary<Type, Type> m_primitiveTypes;

            // all keys CanBeNull
            private Dictionary<Type, XsContract> m_contractsByType;

            // all keys are values in m_contractsByType
            private Dictionary<XsContract, XsContract> m_requiredContractsByContract;

            // all keys are values in either m_contractsByType or m_requiredContractsByContract
            private Dictionary<XsContract, XsContract> m_canBeEmptyContractsByContract;

            // all constraints are values in m_requiredContractsByContract
            private Dictionary<IEnumerable<XsContract>, XsContract> m_objectsByConstraints;

            // all keys are values in m_requiredContractsByContract and are constrained objects
            private Dictionary<IEnumerable<XsContract>, XsContract> m_enumerationsByElementType;

            private XsContract m_objectContract;
            private XsContract m_enumerationContract;
            private XsContract m_xmlContract;
            private XsContract m_stringContract;
            #endregion

            #region Constructor
            internal XsContractCache(XsAssembly assembly) {
                m_assembly = assembly;
                m_contractsByType = new Dictionary<Type, XsContract>();
                m_requiredContractsByContract = new Dictionary<XsContract, XsContract>();

                // primitives
                m_primitiveTypes =
                   (from o in m_assembly.Assembly.GetTypes()
                    let attribute = o.GetAttribute<XsContractAttribute>()
                    where attribute != null && attribute.IsPrimitive
                    select new {
                        MetadataType = o,
                        PrimitiveType = attribute.DeserializedType
                    }).ToDictionary(o => o.PrimitiveType, o => o.MetadataType);

                // normalize IEnumerable
                m_primitiveTypes[typeof(IEnumerable)] =
                    m_primitiveTypes.GetValueOrDefault(typeof(IEnumerable<object>)) ??
                    typeof(IEnumerable<object>);

                // canBeEmpty
                m_canBeEmptyContractsByContract = new Dictionary<XsContract, XsContract>();

                // object constraints
                m_objectsByConstraints = new Dictionary<IEnumerable<XsContract>, XsContract>(
                    AnyEqualityComparer.GetEnumerableComparer<XsContract>());

                // enumeration constraints
                m_enumerationsByElementType = new Dictionary<IEnumerable<XsContract>, XsContract>(
                    AnyEqualityComparer.GetEnumerableComparer<XsContract>());
            }
            #endregion

            #region Internal Members
            internal XsContract GetContractOrNull(Type type) {
                if (type == null)
                    return null;

                // dig out type from nullable, enumeration, runtimeType cases
                bool isEnumeration;
                var metadataType = GetMetadataType(type, out isEnumeration);

                // resolve primitive types
                metadataType = m_primitiveTypes.GetValueOrDefault(metadataType) ?? metadataType;

                // type must be in this assembly to be cached here
                if (metadataType.Assembly != m_assembly.Assembly)
                    return null;

                // test for nullable, enumeration, runtimeType cases
                XsContract contract = null;
                if (type != metadataType) {
                
                    // enumeration
                    if (isEnumeration) {
                        var elementContract = GetContractOrNull(metadataType);
                        if (elementContract != null)
                            contract = EnumerationContract.MakeConstrainedContract(elementContract);
                    
                    // nullable or runtimeType
                    } else
                        contract = GetContractOrNull(metadataType);

                // try cache or activate 
                } else {

                    // try cache
                    contract = m_contractsByType.GetValueOrDefault(metadataType);
                    
                    // activate
                    if (contract == null) {
                        contract = XsContract.Activate(metadataType, false);

                        // cache
                        if (contract != null) {
                            m_contractsByType.Add(metadataType, contract);
                            XsLoader.RaiseOnContractLoad(contract);
                        }
                    }
                }

                return contract;
            }
            internal XsContract MakeRequired(XsContract contract, bool isRequired) {
                // trivial cases
                if (contract.IsRequired == isRequired)
                    return contract;

                // constrained object\enumeration
                if (contract.Constraints().Any()) {

                    if (contract.IsObject)
                        return MakeConstrainedObject(isRequired, contract.Constraints());

                    if (contract.IsEnumeration && contract.Constraints().First() != ObjectContract)
                        return MakeConstrainedEnumeration(contract, contract.Constraints());
                }

                XsContract result = null;

                if (contract.IsRequired) {
                    result = XsLoader.GetContract(contract.MetadataType);

                } else {
                    // check cache
                    result = m_requiredContractsByContract.GetValueOrDefault(contract);

                    // activate and cache
                    if (result == null)
                        m_requiredContractsByContract[contract] = result =
                            XsContract.Activate(contract.MetadataType, isRequired);
                }

                return result.MakeCanBeEmpty(contract.CanBeEmpty);
            }
            internal XsContract MakeConstrainedObject(bool isRequired, IEnumerable<XsContract> constraints) {
                var cannonicalConstraints =

                    // remove duplicates
                    constraints.Distinct()

                    // remove null
                    .Where(o => o != null)

                    // replace any object constraint with it's constraints
                    .Union(constraints
                            .Where(o => o.IsObject)
                            .SelectMany(o => o.Constraints()))

                    // remove any object constraints
                    .ExceptWhere(o => o.IsObject)

                    // order the constraints 
                    .OrderBy(o => o.MetadataType.AssemblyQualifiedName)

                    // must be required
                    .Select(o => o.MakeRequired())

                    // evaluate
                    .ToArray();

                // get object contract
                var contract = ObjectContract;
                if (isRequired)
                    contract = contract.MakeRequired();

                // if there are no constraints then simply return the object
                if (cannonicalConstraints.None())
                    return contract;

                // key = object + constraints
                var key = new List<XsContract>();
                key.Add(contract);
                key.AddRange(cannonicalConstraints);

                // try cache
                XsContract cachedContract;
                if (!m_objectsByConstraints.TryGetValue(key.ToArray(), out cachedContract)) {
                    var objectContract = m_assembly.GetContract(typeof(object));
                    cachedContract = XsContract.ActivateObject(objectContract.MetadataType, isRequired, cannonicalConstraints);

                    if (cachedContract == null)
                        throw new ArgumentException();

                    m_objectsByConstraints[key] = cachedContract;
                }
                return cachedContract;
            }
            internal XsContract MakeConstrainedEnumeration(XsContract contract, IEnumerable<XsContract> constraints) {
                if (!contract.IsEnumeration)
                    throw new ArgumentException();

                var elementContract = MakeConstrainedObject(true, constraints);

                if (elementContract == ObjectContract)
                    return contract;

                // key = enumeration + constrained object
                var key = new List<XsContract>();
                key.Add(contract);
                key.Add(elementContract);

                XsContract cachedContract;
                if (!m_enumerationsByElementType.TryGetValue(key.ToArray(), out cachedContract)) {
                    cachedContract = XsContract.ActivateEnumerable(
                        contract.MetadataType, contract.IsRequired, contract.CanBeEmpty, elementContract);

                    if (cachedContract == null)
                        throw new ArgumentException();

                    m_enumerationsByElementType[key] = cachedContract;
                }

                return cachedContract;
            }
            internal XsContract MakeCanBeEmpty(XsContract contract, bool canBeEmpty) {
                // trivial case
                if (contract.CanBeEmpty == canBeEmpty)
                    return contract;

                // unify object
                if (contract.IsObject)
                    return contract;

                // check cannonical contract (enums with a named default value are CanBeEmpty by default)
                var cannonicalContract = XsLoader.GetContract(contract.MetadataType).MakeRequired(contract.IsRequired);
                if (cannonicalContract.CanBeEmpty == canBeEmpty)
                    return cannonicalContract;

                // check cache
                var cachedContract = m_canBeEmptyContractsByContract.GetValueOrDefault(contract);
                if (cachedContract != null)
                    return cachedContract;

                // activate and cache
                cachedContract = XsContract.ActivateCanBeEmpty(contract.MetadataType, contract.IsRequired, canBeEmpty);
                if (cachedContract == null)
                    throw new ArgumentException();

                m_canBeEmptyContractsByContract[contract] = cachedContract;
                return cachedContract;
            }

            internal XsContract ObjectContract {
                get {
                    if (m_objectContract == null)
                        m_objectContract = GetContractOrNull(typeof(object));
                    return m_objectContract;
                }
            }
            internal XsContract EnumerationContract {
                get {
                    if (m_enumerationContract == null)
                        m_enumerationContract = GetContractOrNull(typeof(IEnumerable<object>));
                    return m_enumerationContract;
                }
            }
            internal XsContract XmlContract {
                get {
                    if (m_xmlContract == null)
                        m_xmlContract = GetContractOrNull(typeof(XElement));
                    return m_xmlContract;
                }
            }
            internal XsContract StringContract {
                get {
                    if (m_stringContract == null)
                        m_stringContract = GetContractOrNull(typeof(string));
                    return m_stringContract;
                }
            }
            #endregion
        }
        #endregion

        #region Static Public Members
        public static XsAssembly InfosetAssembly {
            get {
                if (m_infosetAssembly == null)
                    m_infosetAssembly = GetExecutingAssembly();
                return m_infosetAssembly; 
            }
        }
        public static XsAssembly GetExecutingAssembly() {
            var result = XsAssemblyCache.GetAssembly(Assembly.GetCallingAssembly());
            return result;
        }
        public static IEnumerable<XsAssembly> Assemblies() {
            return XsAssemblyCache.Assemblies();
        }
        public static XsAssembly GetAssemblyOrNull(Assembly assembly) {
            var result = XsAssemblyCache.GetAssemblyOrNull(assembly);
            return result;
        }
        public static XsAssembly GetAssembly(Assembly assembly) {
            var result = GetAssemblyOrNull(assembly);
            if (result == null)
                throw new ArgumentException();
            return result;
        }
        public static XsAssembly GetAssemblyOrNull(Type type) {
            if (type == null)
                return null;

            bool isEnumeration;
            type = GetMetadataType(type, out isEnumeration);

            return GetAssemblyOrNull(type.Assembly);
        }
        public static XsAssembly GetAssembly(Type type) {
            var result = GetAssemblyOrNull(type);
            if (result == null)
                throw new ArgumentException();
            return result;
        }
        public static event OnAssemblyLoadDelegate OnAssemblyLoad {
            add { XsAssemblyCache.OnAssemblyLoad += value; }
            remove { XsAssemblyCache.OnAssemblyLoad -= value; }
        }
        #endregion

        #region Static Internal Members
        internal static Type GetMetadataType(Type type, out bool isEnumeration) {
            isEnumeration = false;

            var knownEnumerations = new[] {
                typeof(string), 
                typeof(IEnumerable), 
                typeof(IEnumerable<object>)
            };

            // enumerable
            if (typeof(IEnumerable).IsAssignableFrom(type) && !knownEnumerations.Contains(type)) {
                isEnumeration = true;
                return type.GetEnumerationElementType();
            }

            // unNullify
            if (type.IsNullable()) {
                type = type.UnNullify();
                return type;
            }

            // runtimeType
            if (XsAssembly.IsRuntimeType(type)) {

                // dig out the first non-runtimeType in the hierarhcy
                type = type.ToLinkList(o => o.BaseType).First(o => !XsAssembly.IsRuntimeType(o));
                return type;
            }

            return type;
        }
        internal static bool IsRuntimeType(Type type) {
            return s_runtimeTypes.Contains(type.GetGenericTypeDefinitionOrType());
        }
        internal static Type GetTypeOrNull(XName xName) {
            return s_typeByXName.GetValueOrDefault(xName);
        }
        #endregion

        #region Static Constructor
        static XsAssembly() {
            s_typeByXName = new Dictionary<XName, Type>();
            s_runtimeTypes = new HashSet<Type>();

            s_runtimeTypes.AddRange(
                typeof(ValueType),
                typeof(Enum),
                typeof(Attribute),
                typeof(Exception));

            XsAssemblyCache.Initialize();
        }
        #endregion

        #region Static Private Members
        private static Dictionary<XName, Type> s_typeByXName;
        private static HashSet<Type> s_runtimeTypes;
        private static XsAssembly m_infosetAssembly;
        #endregion

        #region Private Data Members
        private Assembly m_assembly;
        private IEnumerable<Type> m_types;
        private Dictionary<XNamespace, XsNamespace> m_namespaces;
        private Dictionary<string, XsNamespace> m_namespaceByPrefix;
        private XsSchema m_contractSchema;
        private XsSchema m_attributeSchema;

        private XsContractCache m_cache;
        private XsLoaderOptions m_options;
        #endregion

        #region Constructor
        internal XsAssembly(Assembly assembly) {
            m_assembly = assembly;

            // namespaces
            m_namespaces = 
                assembly.GetAttributes<XsNamespaceAttribute>()
                .ToDictionary(o => (XNamespace)o.Namespace, o => new XsNamespace(this, o));
            m_namespaceByPrefix = new Dictionary<string, XsNamespace>(StringComparer.OrdinalIgnoreCase);
            m_namespaceByPrefix.AddRange(Namespaces(), o => o.Prefix);

            // runtime type
            s_runtimeTypes.AddRange(m_assembly.GetTypes().Where(o => o.IsDefined<XsRuntimeContractAttribute>()));

            // contract schema
            var contractSchemaAttribute = assembly.GetAttribute<XsContractSchemaAttribute>();
            if (contractSchemaAttribute != null)
                m_contractSchema = new XsSchema(contractSchemaAttribute);

            // attribute schema
            var attributeSchemaAttribute = assembly.GetAttribute<XsAttributeSchemaAttribute>();
            if (attributeSchemaAttribute != null)
                m_attributeSchema = new XsSchema(attributeSchemaAttribute);

            // contract & attribute names
            var types =
                from o in m_assembly.GetTypes()
                let schema = GetSchema(o)
                where schema != null
                select new { 
                    Schema = schema,
                    FullName = schema.GetFullName(o), 
                    Type = o,
                };
            m_types = types.Select(o => o.Type).ToArray();
            s_typeByXName.AddRange(types, o => o.FullName, o => o.Type);

            foreach (var g in types.GroupBy(o => o.Schema))
                g.Key.Initialize(this, g.Select(o => o.Type));

            m_cache = new XsContractCache(this); 
        }
        #endregion

        #region Internal Members
        internal XsSchema GetSchema(Type type) {
            if (!type.IsDefined<XsObjectAttribute>())
                return null;

            var schema = ContractSchema;
            if (type.IsDefined<XsAnnotationContract>()) {
                schema = AttributeSchema;

            } else if (type.IsDefined<XsSimpleContractAttribute>()) {
                if (type.GetAttribute<XsSimpleContractAttribute>().IsAttributeSchemaOnly)
                    schema = AttributeSchema;

            } else if (type.IsDefined<XsListContractAttribute>()) {
                if (type.GetAttribute<XsListContractAttribute>().IsAttributeSchemaOnly)
                    schema = AttributeSchema;
            }

            return schema;
        }
        internal XsContract MakeRequired(XsContract contract, bool required) {
            return m_cache.MakeRequired(contract, required);
        }
        internal XsContract MakeCanBeEmpty(XsContract contract, bool canBeEmpty) {
            return m_cache.MakeCanBeEmpty(contract, canBeEmpty);
        }
        internal XsContract MakeConstrainedObject(IEnumerable<XsContract> constraints) {
            return m_cache.MakeConstrainedObject(false, constraints);
        }
        #endregion

        #region Public Members
        public string Name { get { return m_assembly.GetName().Name; } }
        public Assembly Assembly { get { return m_assembly; } }
        public XNamespace GetNamespace(string prefix) {
            if (string.IsNullOrEmpty(prefix))
                throw new ArgumentNullException();

            var ns = m_namespaceByPrefix.GetValueOrDefault(prefix);
            if (ns == null)
                throw new ArgumentException();

            return ns.Namespace;
        }
        public IEnumerable<XsNamespace> Namespaces() { 
            return m_namespaces.Values;
        }
        public XsSchema ContractSchema { 
            get { return m_contractSchema; } 
        }
        public XsSchema AttributeSchema { 
            get { return m_attributeSchema; } 
        }

        public IEnumerable<XsContract> Contracts() {
            return m_types.Select(o => XsLoader.GetContract(o));
        }
        public XsContract GetContractOrNull(Type type) {
            return m_cache.GetContractOrNull(type);
        }
        public XsContract GetContract(Type type) {
            var result = GetContractOrNull(type);
            if (result == null)
                throw new ArgumentException();
            return result;
        }
        
        public XsContract GetContractOrNull(string name) {
            var schema = ContractSchema;
            if (schema == null)
                throw new ArgumentException();
            return schema.GetContractOrNull(name);
        }
        public XsContract GetContract(string name) {
            var result = GetContractOrNull(name);
            if (result == null)
                throw new ArgumentException();
            return result;
        }

        public XsContract GetContractOrNull(object instance) {
            return GetContractOrNull(instance, Enumerable.Empty<XsContract>());
        }
        public XsContract GetContract(object instance) {
            var result = GetContractOrNull(instance);
            if (result == null)
                throw new ArgumentException();
            return result;
        }

        public XsContract GetContractOrNull(object instance, IEnumerable<XsContract> constraints) {
            if (instance == null)
                return null;
            
            if (instance is TypedObject)
                return ((TypedObject)instance).Contract;

            if (instance is Type)
                return GetContractOrNull((Type)instance);

            XsContract result = GetContractOrNull(instance.GetType());
            if (constraints == null || constraints.None())
                return result;
            
            var candidates = constraints.Where(o => o.DeserializedType.IsAssignableFrom(instance)).ToArray();
            var constraint = candidates.Where(o => candidates.All(x => o == x || o.IsDerivationOf(x))).SingleOrDefault();
         
            // ambiguous without constraints
            if (result == null)
                result = constraint;

            // type hole
            else if (constraint == null)
                throw new ArgumentException("Object of type '" + instance.GetType().Name + "' cannot be resolved.");
                
            // country => countryInfo
            else if (!result.IsDerivationOf(constraint))
                result = constraint;

            return result;
        }
        public XsContract GetContract(object instance, IEnumerable<XsContract> constraints) {
            if (instance == null)
                throw new ArgumentException();

            var result = GetContractOrNull(instance, constraints);

            if (result == null)
                throw new ArgumentException();

            return result;
        }

        public XsContract MakeConstrainedEnumeration(IEnumerable<XsContract> constraints) {
            var contract = GetContract(typeof(IEnumerable));
            return m_cache.MakeConstrainedEnumeration(contract, constraints);
        }

        public XsContract ObjectContract {
            get { return m_cache.ObjectContract; }
        }
        public XsContract EnumerationContract {
            get { return m_cache.EnumerationContract; }
        }
        public XsContract XmlContract {
            get { return m_cache.XmlContract; }
        }
        public XsContract StringContract {
            get { return m_cache.StringContract; }
        }
        #endregion

        #region Object Overrides
        public sealed override string ToString() {
 	        return "{0}, {1} ({2})".Substitute(Name, ContractSchema, AttributeSchema);
        }
        #endregion
    }
    public sealed class XsLoaderOptions {
        public bool Flatten { get; set; }
        public bool SkipVerification { get; set; }
    }
    public static class XsLoader {

        #region Static Public Members
        public static XsLoaderOptions Options {
            get { 
                if (s_options == null)
                    s_options = new XsLoaderOptions() { 
                        SkipVerification = false,
                        Flatten = false 
                    };
                return s_options; 
            }
            set {
                if (s_options != null)
                    throw new InvalidOperationException();
                s_options = value;
            }
        }
        #endregion

        #region Static Public Members (Contracts)
        public static IEnumerable<XsContract> Contracts() {
            return XsAssembly.Assemblies().SelectMany(o => o.Contracts());            
        }

        internal static XsContract GetContractOrNull(XsAssembly callingAssembly, object target) {
            if (target == null)
                return null;

            // get the type of the instance or the type itself
            var type = target as Type;
            if (type == null)
                type = target.GetType();

            XsContract result;

            // resolve against the type's assembly
            var targetAssembly = XsAssembly.GetAssemblyOrNull(type);
            if (targetAssembly != null) {
                result = targetAssembly.GetContractOrNull(target);
                if (result != null)
                    return result;
            }

            // resolve against the calling assembly
            if (callingAssembly != null) {
                result = callingAssembly.GetContractOrNull(target);
                if (result != null)
                    return result;
            }

            // resolve against the infoset assembly
            result = XsAssembly.InfosetAssembly.GetContractOrNull(target);
            return result;
        }
        public static XsContract GetContractOrNull(Type type) {
            var assembly = XsAssembly.GetAssemblyOrNull(Assembly.GetCallingAssembly());
            return GetContractOrNull(assembly, type);
        }
        public static XsContract GetContract(Type type) {
            var assembly = XsAssembly.GetAssemblyOrNull(Assembly.GetCallingAssembly());
            var result = GetContractOrNull(assembly, type);
            if (result == null)
                throw new ArgumentException();
            return result;
        }

        public static XsContract GetContractOrNull(object instance) {
            var assembly = XsAssembly.GetAssembly(Assembly.GetCallingAssembly());
            return GetContractOrNull(assembly, instance);
        }
        public static XsContract GetContract(object instance) {
            var assembly = XsAssembly.GetAssembly(Assembly.GetCallingAssembly());
            var result = GetContractOrNull(assembly, instance);
            if (result == null)
                throw new ArgumentException();
            return result;
        }

        public static XsContract GetContractOrNull(XName xName) {
         
            // if no namespace is provided uses the calling assemblies ContractSchema
            if (xName.Namespace == XNamespace.None) {
                var assembly = XsAssembly.GetAssembly(Assembly.GetCallingAssembly());
                if (assembly == null || assembly.ContractSchema == null)
                    return null;
                xName = assembly.ContractSchema.Namespace + xName.LocalName;
            }
            return GetContractOrNull(XsAssembly.GetTypeOrNull(xName));
        }
        public static XsContract GetContract(XName xName) {
            var result = GetContractOrNull(xName);
            if (result == null)
                throw new ArgumentException();
            return result;
        }

        internal static XsContract GetContractOrNull(XsAssembly assembly, string name) {
            if (name == null)
                return null;

            // resolve against the calling assembly
            if (assembly != null) {
                var result = assembly.GetContractOrNull(name);
                if (result != null)
                    return result;
            }

            // resolve against the infoset assembly
            return XsAssembly.InfosetAssembly.GetContractOrNull(name);
        }
        public static XsContract GetContractOrNull(string name) {
            var assembly = XsAssembly.GetAssembly(Assembly.GetCallingAssembly());
            return GetContractOrNull(assembly, name);
        }
        public static XsContract GetContract(string name) {
            var assembly = XsAssembly.GetAssembly(Assembly.GetCallingAssembly());
            var result = GetContractOrNull(assembly, name);
            if (result == null)
                throw new ArgumentException();
            return result;
        }

        public static XsContract ObjectContract {
            get { return XsAssembly.InfosetAssembly.ObjectContract; }
        }
        public static XsContract EnumerationContract {
            get { return XsAssembly.InfosetAssembly.EnumerationContract; }
        }
        public static XsContract XmlContract {
            get { return XsAssembly.InfosetAssembly.XmlContract; }
        }
        public static XsContract StringContract {
            get { return XsAssembly.InfosetAssembly.StringContract; }
        }
        #endregion

        #region Static Public Members (EnumValues)
        public static XsEnum GetEnumValueOrNull(object value) {
            if (value == null)
                return null;

            var contract = GetContract(value.GetType());
            var result = contract.Enums().SingleOrDefault(o => object.Equals(o.SerializedValue, value));
            return result;
        }
        public static XsEnum GetEnumValue(object value) {
            var result = GetEnumValueOrNull(value);

            if (result == null)
                throw new ArgumentException();

            return result;
        }
        public static event OnContractLoadDelegate OnContractLoad;
        #endregion

        #region Static Internal Members
        internal static void RaiseOnContractLoad(XsContract contract) {
            if (OnContractLoad != null)
                OnContractLoad(contract);
        }
        #endregion

        #region Static Private Data Members
        private static XsLoaderOptions s_options;
        #endregion
    }
    #endregion
}

namespace King.Infoset.Reflection {

    #region Base Constracts                 (Object, Contract)
    public abstract class XsObject : ICustomAttributeProviderEx {

        #region Private Data Members
        private XsAssembly m_assembly;
        private ICustomAttributeProvider m_provider;
        private string m_summary;
        private string m_name;
        private string m_schemaName;
        private XName m_fullName;
        #endregion

        #region Constructor
        internal XsObject(XsAssembly assembly) {
            m_assembly = assembly;
        }
        internal XsObject(ICustomAttributeProvider provider) {

            // custom attribute provider
            m_provider = provider;
            m_assembly = XsAssembly.GetAssembly(provider.GetAssembly());

            // documentation
            var documentation = DocumentationLoader.GetDocumentation(provider);
            if (documentation != null)
                m_summary = documentation.Summary;

            // implicit name
            m_name = provider.GetName();

            // explicit name
            var attribute = provider.GetAttribute<XsObjectAttribute>();
            if (attribute != null && attribute.Name != null)
                m_name = attribute.Name;

            // explicit schema name
            m_schemaName = m_name;
            if (attribute != null && attribute.SchemaName != null)
                m_schemaName = attribute.SchemaName;
        }
        #endregion

        #region Internal Members
        internal MemberInfo MemberInfo {
            get { return m_provider as MemberInfo; }
        }
        internal ParameterInfo ParameterInfo {
            get { return m_provider as ParameterInfo; }
        }
        #endregion

        #region Public Members
        public XsAssembly Assembly {
            get { return m_assembly; } 
        }
        public abstract XsSchema Schema { get; }
        public string Name { 
            get { return m_name; } 
        }
        public string SchemaName {
            get {
                if (!Schema.PreserveCase && char.IsUpper(m_schemaName[0]))
                    m_schemaName = m_schemaName.ToLowerFirst();
                return m_schemaName;
            }
        }
        public ICustomAttributeProvider AttributeProvider {
            get { return m_provider; }
        }
        public string Summary { 
            get { return m_summary; } 
        }
        public XName FullName {
            get {
                if (m_fullName == null)
                    m_fullName = Namespace + SchemaName;
                return m_fullName;
            }
        }
        public XNamespace Namespace {
            get { return Schema.Namespace; }
        }
        #endregion

        #region ICustomAttributeProvider Members
        public object[] GetCustomAttributes(bool inherit) {
            return m_provider.GetCustomAttributes(inherit);
        }
        public object[] GetCustomAttributes(Type attributeType, bool inherit) {
            return m_provider.GetCustomAttributes(attributeType, inherit);
        }
        public bool IsDefined(Type attributeType, bool inherit) {
            return m_provider.IsDefined(attributeType, inherit);
        }
        public ICustomAttributeProvider ReflectionInfo {
            get { return m_provider; }
        }
        #endregion
    }
    public abstract partial class XsContract : XsObject {
        
        #region Static Internal Members
        internal static XsContract Activate(Type metadataType, bool isRequired) {
            XsContract contract = null;

            // object
            if (metadataType.IsDefined<XsObjectContractAttribute>())
                contract = ActivateObject(metadataType, isRequired, Enumerable.Empty<XsContract>());

            // xml
            else if (metadataType.IsDefined<XsXmlContractAttribute>())
                contract = new XsXmlContract(metadataType, isRequired);

            // group
            else if (metadataType.IsDefined<XsGroupContractAttribute>())
                contract = new XsGroupContract(metadataType, isRequired);

            // complex
            else if (metadataType.IsDefined<XsComplexContractAttribute>())
                contract = new XsComplexContract(metadataType, isRequired);

            // decimal
            else if (metadataType.IsDefined<XsDecimalContractAttribute>())
                contract = new XsDecimalContract(metadataType, isRequired);

            // boolean
            else if (metadataType.IsDefined<XsBooleanContractAttribute>())
                contract = new XsBooleanContract(metadataType, isRequired);

            // union
            else if (metadataType.IsDefined<XsUnionContractAttribute>())
                contract = new XsUnionContract(metadataType, isRequired);

            // annotation
            else if (metadataType.IsDefined<XsAnnotationContractAttribute>())
                contract = new XsAnnotationContract(metadataType, isRequired);

            // try canBeEmpty contracts
            if (contract == null)
                contract = ActivateCanBeEmpty(metadataType, isRequired, null);

            return contract;
        }
        internal static XsContract ActivateCanBeEmpty(Type metadataType, bool isRequired, bool? canBeEmpty) {

            XsContract contract = null;
            
            // enumerable
            if (metadataType.IsDefined<XsEnumerationContractAttribute>())
                contract = ActivateEnumerable(metadataType, isRequired, canBeEmpty, null);

            // anySimpleType
            else if (metadataType == typeof(XsAnySimpleType))
                contract = new XsAnySimpleContract(metadataType, isRequired, canBeEmpty);

            // string
            else if (metadataType.IsDefined<XsStringContractAttribute>())
                contract = new XsStringContract(metadataType, isRequired, canBeEmpty);

            // enum
            else if (metadataType.IsDefined<XsEnumContractAttribute>())
                contract = new XsEnumContract(metadataType, isRequired, canBeEmpty);

            // constants
            else if (metadataType.IsDefined<XsConstantsContractAttribute>())
                contract = new XsConstantsContract(metadataType, isRequired, canBeEmpty);

            return contract;
        }
        internal static XsContract ActivateEnumerable(Type metadataType, bool isRequired, bool? canBeEmpty, XsContract elementContract) {
            XsContract contract = new XsEnumerableContract(metadataType, isRequired, canBeEmpty, elementContract);
            return contract;
        }
        internal static XsContract ActivateObject(Type metadataType, bool isRequired, IEnumerable<XsContract> constraints) {
            XsContract contract = new XsObjectContract(metadataType, isRequired, constraints);
            return contract;
        }
        #endregion

        #region Private Data Members
        private Type m_metadataType;
        private bool m_isRequired;
        private string m_metadataName;
        private Type m_clientType;
        private bool m_isPrimitive;

        private MethodInfo m_serialize;
        private bool m_serializeCached;

        private MethodInfo m_deserialize;
        private bool m_deserializeCached;

        private MethodInfo m_serializeCsv;
        private bool m_serializeCsvCached;

        private MethodInfo m_deserializeCsv;
        private bool m_deserializeCsvCached;
        #endregion

        #region Constructor
        internal XsContract(Type metadataType, bool isRequired)
            : base(metadataType) {

            // metadataType, metadataName
            m_metadataType = metadataType;
            m_metadataName = metadataType.Name;

            // name
            var attribute = m_metadataType.GetAttribute<XsContractAttribute>();
            m_isPrimitive = attribute.IsPrimitive;
            
            if (attribute.Name != null)
                m_metadataName = attribute.Name;

            var clientTypeAttribute = m_metadataType.GetAttribute<XsClientTypeAttribute>();
            if (clientTypeAttribute != null)
                m_clientType = clientTypeAttribute.Type;

            m_isRequired = isRequired;
        }
        #endregion

        #region Public Members (Identity, Discriminators)
        // identity
        public Type MetadataType { 
            get { return m_metadataType; } 
        }
        public virtual Type DeserializedType {
            get { return MetadataType; }
        }
        public abstract Type SerializedType { get; }
        public override XsSchema Schema { 
            get { return Assembly.ContractSchema; } 
        }
        public virtual Type ClientType {
            get { return m_clientType; }
        }
        public virtual XsContract ClientContract {
            get { 
                var contract = XsLoader.GetContractOrNull(m_clientType);
                if (contract == null)
                    return null;
                contract = contract.MakeCanBeEmpty(CanBeEmpty);
                contract = contract.MakeRequired(IsRequired);
                return contract;
            }
        }

        public bool IsXsd {
            get { return Namespace == XsAssembly.GetExecutingAssembly().ContractSchema.Namespace; }
        }
        public XsContract BaseXsdContract {
            get { return BaseContract.ToLinkList(o => o.BaseContract).FirstOrDefault(o => o.IsXsd); }
        }
        public bool IsPrimitive {
            get { return m_isPrimitive; }
        }

        public bool IsMetadataAlias {
            // the DeserializedType can be used in code to specify this Contract 
            get {
                // vacuously true if the DeserializedType is the MetadataType
                if (!IsAlias)
                    return true;

                if (this.IsObject || this.IsEnumeration || this.IsXml)
                    return true;

                // a IEnumerable<T> is a metadata alias if T is a metadata alias
                if (IsEnumeration && Constraints().OnlyOne())
                    return Constraints().Single().IsMetadataAlias;
                
                // by definition primitive DeserializedType's can be used in declarations in place of the MetadataType
                return IsPrimitive; 
            }
        }
        public bool IsAlias { 
            // the MetadataType is the DeserializedType
            get {
                // no clr type can represent a multi-constrainted Contract
                if (Constraints().MoreThanOne())
                    return true;

                // a IEnumerable<T> is an alias if T is an alias
                if (IsEnumeration)
                    return Constraints().Single().IsAlias;

                // If DeserializedType is not the MetadataType then this is an alias
                var result = DeserializedType.UnNullify() != MetadataType;
                return result;
            } 
        }

        // discriminators
        public bool IsObject { get { return this is XsObjectContract; } }
        public bool IsEnumeration { get { return this is XsEnumerableContract; } }
        public bool IsXml { get { return this is XsXmlContract; } }
        public bool IsComplex { get { return this is XsComplexContract; } }
        public bool IsGroup { get { return this is XsGroupContract; } }
        public bool IsSimple { get { return this is XsSimpleContract; } }
        public bool IsList { get { return this is XsListContract; } }
        public bool IsUnion { get { return this is XsUnionContract; } }
        public bool IsEnum { get { return this is XsEnumContract; } }
        public bool IsConstant { get { return this is XsConstantsContract; } }
        public bool IsString { get { return this is XsStringContract; } }
        public bool IsDecimal { get { return this is XsDecimalContract; } }
        public bool IsBoolean { get { return this is XsBooleanContract; } }
        public bool IsAnnotation { get { return this is XsAnnotationContract; } }
        public bool IsSimpleContent { get { return Members().Any(o => o.IsSimpleContent); } }
        #endregion

        #region Public Members (Required, Empty, Constraints)
        // content
        public virtual bool ContentIsSimple { get { return false; } }
        public virtual bool ContentIsComplex { get { return false; } }

        // required
        public bool IsRequired {
            get { return m_isRequired; }
        }
        public bool IsOptional {
            get { return !IsRequired; }
        }
        public XsContract MakeRequired() {
            return MakeRequired(true);
        }
        public XsContract MakeOptional() {
            return MakeRequired(false);
        }
        public XsContract MakeRequired(bool required) {
            if (required == IsRequired)
                return this;

            return Assembly.MakeRequired(this, required);
        }

        // canBeEmpty
        public virtual bool CanBeEmpty {
            get { return false; }
        }
        public XsContract MakeCannotBeEmpty() {
            return MakeCanBeEmpty(false);
        }
        public XsContract MakeCanBeEmpty() {
            return MakeCanBeEmpty(true);
        }
        public XsContract MakeCanBeEmpty(bool canBeEmpty) {
            if (CanBeEmpty == canBeEmpty)
                return this;

            return Assembly.MakeCanBeEmpty(this, canBeEmpty);
        }

        // constraints, elementContract, lists
        public virtual IEnumerable<XsContract> Lists() {
            return Enumerable.Empty<XsContract>();
        }
        public virtual XsContract ElementContract {
            get { return null; }
        }
        public virtual IEnumerable<XsContract> Constraints() { 
            return Enumerable.Empty<XsContract>();
        }
        public IEnumerable<Type> MetadataTypeConstraints() {
            return Constraints().Select(o => o.MetadataType).Distinct();
        }
        public IEnumerable<Type> RuntimeTypeConstraints() {
            return Constraints().Select(o => o.DeserializedType).Distinct();
        }
        public virtual XsContract MakeConstrainedContract(IEnumerable<XsContract> constraints) {
            throw new InvalidOperationException();
        }
        public XsContract MakeConstrainedContract(params XsContract[] constraints) {
            return MakeConstrainedContract((IEnumerable<XsContract>)constraints);
        }
        public virtual XsContract ContstraintsCommonBaseContract {
            get { throw new InvalidOperationException(); }
        }
        #endregion

        #region Public Members (GetContract)
        public XsContract GetContract(object instance) {
            var result = GetContractOrNull(instance);
            if (result == null)
                throw new ArgumentException();
            return result;
        }
        public virtual XsContract GetContractOrNull(object instance) {
            return Assembly.GetContractOrNull(instance, new[] { this });
        }
        #endregion

        #region Public Members (Hierarchy, Assignability)
        public abstract XsContract BaseContract { get; }
        public virtual bool IsAbstract {
            get { return MetadataType.IsAbstract; }
        }
        public virtual bool IsSealed {
            get { return MetadataType.IsSealed; }
        }
        public virtual bool IsDeriveByRestriction {
            get { return false; }
        }
        public bool IsDeriveByExtension {
            get { return !IsDeriveByRestriction; }
        }
        public virtual bool IsRestriction {
            get { return false; }
        }
        public bool IsExtension {
            get { return !IsRestriction; }
        }
        public bool IsDerivationOf(Type type) {
            return IsDerivationOf(GetContract(type));
        }
        public bool IsDerivationOf(XsContract contract) {
            if (contract == null)
                throw new ArgumentNullException();

            if (contract.IsRequired != IsRequired)
                contract = contract.MakeRequired(IsRequired);

            if (BaseContract == null)
                return false;

            if (BaseContract == contract)
                return true;

            return BaseContract.IsDerivationOf(contract);
        }
        public bool IsReplaceableWith(XsContract contract) {

            if (contract == null)
                throw new ArgumentNullException();

            if (IsObject && Constraints().Any())
                return Constraints().Any(o => o.IsReplaceableWith(contract));

            if (!contract.CanBeEmpty && this.CanBeEmpty)
                return IsReplaceableWith(contract.MakeCanBeEmpty());
            else
                return contract == this || contract.IsDerivationOf(this);
        }
        #endregion

        #region Public Members (Basic SimpleContract)
        public virtual Regex Regex {
            get { return null; }
        }
        public virtual void TestXmlConstraints(string source) {
        }
        public virtual void TestConstraints(object value) {
        }
        public virtual int? MaxLength { get { throw new InvalidOperationException(); } }
        public virtual int? MinLength { get { throw new InvalidOperationException(); } }
        public virtual long? MaxInclusive { get { throw new InvalidOperationException(); } }
        public virtual long? MinInclusive { get { throw new InvalidOperationException(); } }
        public virtual long? MaxExclusive { get { throw new InvalidOperationException(); } }
        public virtual long? MinExclusive { get { throw new InvalidOperationException(); } }
        public virtual int? TotalDigits { get { throw new InvalidOperationException(); } }
        public virtual int? FractionDigits { get { throw new InvalidOperationException(); } }
        #endregion

        #region Public Members (Lists SimpleContract)
        public virtual bool IsFlags {
            get { return false; }
        }
        public virtual IEnumerable<XsMask> Masks() {
            return Enumerable.Empty<XsMask>();
        }
        public virtual IEnumerable<XsEnum> Enums() {
            return Enumerable.Empty<XsEnum>();
        }
        public virtual IEnumerable<XsEnum> Enums(object value) {
            throw new InvalidOperationException();
        }
        public virtual IEnumerable<XsEnum> CannonicalEnums(object value) {
            throw new InvalidOperationException();
        }
        public virtual object ToObject(IEnumerable<XsEnum> flags) {
            throw new InvalidOperationException();
        }
        public virtual IEnumerable<XsConstant> Constants() {
            return Enumerable.Empty<XsConstant>();
        }
        #endregion

        #region Public Members (ContractMembers, Operations)
        // ContractMembers
        public virtual IEnumerable<XsMember> Members() {
            return Enumerable.Empty<XsMember>();
        }
        public virtual IEnumerable<XsMember> DeclaredMembers() {
            return Enumerable.Empty<XsMember>();
        }

        public XsMember GetDeclaredMember(string name) {
            return DeclaredMembers().SingleOrDefault(o => o.Name == name);
        }
        public XsMember GetMember(string name) {
            return Members().SingleOrDefault(o => o.Name == name);
        }

        // Operations
        public virtual XsOperation GetOperation(MethodBase methodBase) { 
            return null; 
        }
        public virtual IEnumerable<XsOperation> DeclaredOperations() {
            return Enumerable.Empty<XsOperation>();
        }
        public virtual IEnumerable<XsOperation> Operations(string name) {
            return Enumerable.Empty<XsOperation>();
        }
        public virtual IEnumerable<XsOperation> Operations(XName name) { 
            return Enumerable.Empty<XsOperation>(); 
        }
        public virtual IEnumerable<XsOperation> Operations() {
            return Enumerable.Empty<XsOperation>();
        }
        #endregion

        #region Public Members (Latebound)
        public virtual object Deserialize(object serializedValue) {
            if (serializedValue == null)
                return null;

            if (!m_deserializeCached) {
                m_deserialize = MetadataType.GetStatic<MethodInfo>("Deserialize", SerializedType);
                m_deserializeCached = true;
            }

            object deserializedValue;
            if (m_deserialize != null)
                deserializedValue = m_deserialize.Invoke(null, new object[] { serializedValue });
            else 
                deserializedValue = BaseContract.Deserialize(serializedValue);

            return deserializedValue;
        }
        public object Serialize(object deserializedValue) {
            if (deserializedValue == null)
                return null;

            if (deserializedValue is TypedObject) {
                var typedObject = (TypedObject)deserializedValue;
                return typedObject.Contract.Serialize(typedObject.Object);
            }

            return SerializeImpl(deserializedValue);
        }
        internal virtual object SerializeImpl(object deserializedValue) {
            if (!m_serializeCached) {
                m_serialize = MetadataType.GetStatic<MethodInfo>("Serialize", DeserializedType);
                m_serializeCached = true;
            }

            object serializedValue;
            if (m_serialize == null)
                serializedValue = BaseContract.Serialize(deserializedValue);
            else 
                serializedValue = m_serialize.Invoke(null, new object[] { deserializedValue });

            return serializedValue;
        }

        public virtual object DeserializeXml(string serializedValue) {
            throw new ArgumentException();
        }
        public virtual string SerializeXml(object deserializedValue) {
            throw new ArgumentException();
        }
        public virtual object DeserializeCsv(string serializedValue) {
            if (!m_deserializeCsvCached) {
                m_deserializeCsv = MetadataType.GetStatic<MethodInfo>("DeserializeCsv", typeof(string));
                m_deserializeCsvCached = true;
            }

            object deserializedValue;
            if (m_deserializeCsv != null)
                deserializedValue = m_deserializeCsv.Invoke(null, new object[] { serializedValue });
            else
                deserializedValue = BaseContract.DeserializeCsv(serializedValue);

            return deserializedValue;
        }
        public virtual string SerializeCsv(object deserializedValue) {
            if (deserializedValue == null)
                return null;

            if (!m_serializeCsvCached) {
                m_serializeCsv = MetadataType.GetStatic<MethodInfo>("SerializeCsv", SerializedType);
                m_serializeCsvCached = true;
            }

            object serializedValue;
            if (m_serializeCsv == null)
                serializedValue = BaseContract.SerializeCsv(deserializedValue);
            else
                serializedValue = m_serializeCsv.Invoke(null, new object[] { deserializedValue });

            return (string)serializedValue;
        }
        #endregion

        #region Object Overrides
        public override int GetHashCode() {
            return base.GetHashCode();
        }
        public override bool Equals(object obj) {
            return base.Equals(obj);
        }
        internal string ToStringInternal() {
            return ToStringInternal(false);
        }
        internal string ToStringInternal(bool isConstraint) {
            string result = string.Empty;
            
            result += SchemaName.ToUpperFirst();

            if (CanBeEmpty && !IsEnumeration)
                result += "?";

            if (IsRequired && !isConstraint)
                result += "!";

            var constraints = Constraints();
            if (constraints.Any())
                result += "<" + constraints.StringJoin(", ", o => o.ToStringInternal(true)) + ">";

            return result;
        }
        public override string ToString() {
            var result = ToStringInternal();

            if (IsAlias) {
                result += " (";

                var type = DeserializedType.UnNullify();

                if (type.IsEnum)
                    result += "enum ";

                if (type.IsStruct())
                    result += "struct ";

                result += DeserializedType.ToCSharpNestedToString();

                result += ")";
            }

            if (IsGroup)
                result += ", group";
            else if (IsComplex)
                result += ", complex";
            else if (IsList)
                result += ", list";
            else if (IsSimple)
                result += ", simple";
            else if (IsAnnotation)
                result += ", annotation";

            result += ", " + Assembly.Name;

            return result;
        }
        #endregion
    }
    #endregion

    #region Special Contracts               (Enumerable, Xml, Object, UnconstrainedObject, ConstrainedObject)
    internal sealed class XsEnumerableContract : XsContract {

        #region Private Data Members
        private XsContract m_baseContract;
        private XsContract m_elementContract;
        private IEnumerable<XsContract> m_constraints;
        private Type m_deserializedType;
        private Type m_serializedType;
        private bool m_canBeEmpty;
        #endregion

        #region Constructor
        internal XsEnumerableContract(Type metadataType, bool isRequired, bool? canBeEmpty, XsContract elementContract)
            : base(metadataType, isRequired) {

            if (elementContract == null)
                elementContract = Assembly.GetContract(typeof(object));

            if (!elementContract.IsObject)
                throw new ArgumentException();

            m_elementContract = elementContract;
            m_constraints = new[] { Assembly.MakeConstrainedObject(new XsContract[] { elementContract }) };
            m_serializedType = m_deserializedType = elementContract.DeserializedType.MakeEnumerable();
            //m_serializedType = elementContract.SerializedType.MakeEnumerable();
            m_baseContract = XsLoader.GetContract(metadataType.BaseType);

            m_canBeEmpty = canBeEmpty == null ? true : (bool)canBeEmpty;
        }
        #endregion

        #region Public Members (Identity)
        public sealed override Type DeserializedType {
            get { return m_deserializedType; }
        }
        public sealed override Type SerializedType {
            get { return m_serializedType; }
        }
        public sealed override bool CanBeEmpty {
            get { return m_canBeEmpty; }
        }
        public sealed override bool IsAbstract {
            get { return false; }
        }
        public sealed override XsContract BaseContract {
            get { return m_baseContract; }
        }
        public sealed override Type ClientType {
            get {
                if (ClientContract == null)
                    return null;

                return ClientContract.SerializedType; 
            }
        }
        public sealed override XsContract ClientContract {
            get {
                if (ElementContract.ClientContract == null)
                    return null;

                return MakeConstrainedContract(ElementContract.ClientContract);
            }
        }
        #endregion

        #region Public Members (Constraints)
        public sealed override XsContract ElementContract {
            get { return m_elementContract; }
        }
        public sealed override IEnumerable<XsContract> Constraints() {
            return m_constraints;
        }
        public sealed override XsContract MakeConstrainedContract(IEnumerable<XsContract> constraints) {
            return Assembly.MakeConstrainedEnumeration(constraints);
        }
        public sealed override XsContract GetContractOrNull(object instance) {
            var enumerable = instance as IEnumerable;
            if (enumerable == null || instance is string)
                return null;

            var elementType = enumerable.GetType().GetEnumerationElementType();
            if (!ElementContract.DeserializedType.IsAssignableFrom(elementType))
                return null;

            return this;
        }
        #endregion

        #region Public Members (Latebound)
        public sealed override object Deserialize(object serializedValues) {
            if (serializedValues == null)
                return null;

            var deserializedValues = (IList)typeof(List<>).MakeGenericType(ElementContract.DeserializedType).Activate();
            foreach (var serializedValue in (IEnumerable)serializedValues) {
                if (serializedValue == null)
                    throw new ArgumentException("Enumerations cannot contain null elements.");
                var deserializedValue = ElementContract.Deserialize(serializedValue);
                deserializedValues.Add(deserializedValue);
            }

            return deserializedValues;
        }
        internal sealed override object SerializeImpl(object deserializedValues) {
            if (deserializedValues == null)
                return null;

            var serializedValues = (IList)typeof(List<>).MakeGenericType(ElementContract.SerializedType).Activate();
            foreach (var deserializedValue in (IEnumerable)deserializedValues) {
                if (deserializedValue == null)
                    throw new ArgumentException("Enumerations cannot contain null elements.");
                var serializedValue = ElementContract.Serialize(deserializedValue);
                serializedValues.Add(serializedValue);
            }

            return serializedValues;
        }
        #endregion
    }
    internal sealed class XsXmlContract : XsContract {

        #region Private Data Members
        private XsContract m_baseContract;
        #endregion

        #region Constructor
        internal XsXmlContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {

            if (Assembly == XsAssembly.InfosetAssembly)
                m_baseContract = Assembly.ObjectContract;
            else
                m_baseContract = XsAssembly.InfosetAssembly.XmlContract;
        }
        #endregion

        #region Public Members (Hierarchy)
        public sealed override XsContract BaseContract {
            get { return m_baseContract; }
        }
        public sealed override Type DeserializedType {
            get { return typeof(XElement); }
        }
        public sealed override Type SerializedType {
            get { return typeof(XElement); }
        }

        public sealed override object Deserialize(object serializedValue) {
            return (XElement)serializedValue;
        }
        internal sealed override object SerializeImpl(object deserializedValue) {
            return (XElement)deserializedValue;
        }
        #endregion
    }
    internal sealed class XsObjectContract : XsContract {

        #region Constructor
        internal XsObjectContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {
        }
        #endregion

        #region Private Data Members
        private IEnumerable<XsContract> m_constraints;
        private Type m_deserializedType;
        private Type m_serializedType;
        private XsContract m_baseContract;
        #endregion

        #region Constructor
        internal XsObjectContract(Type metadataType, bool isRequired, IEnumerable<XsContract> constraints)
            : base(metadataType, isRequired) {

            m_constraints = constraints;
            m_deserializedType = constraints.Select(o => o.DeserializedType).GreatestCommonBaseType() ?? typeof(object);
            m_serializedType = constraints.Select(o => o.SerializedType).GreatestCommonBaseType() ?? typeof(object);

            if (Assembly != XsAssembly.InfosetAssembly)
                m_baseContract = XsAssembly.InfosetAssembly.ObjectContract;
        }
        #endregion

        #region Public Members
        public sealed override XsContract BaseContract {
            get { return m_baseContract; }
        }
        public sealed override Type DeserializedType {
            get { return m_deserializedType; }
        }
        public sealed override Type SerializedType {
            get { return m_serializedType; }
        }
        public sealed override IEnumerable<XsContract> Constraints() {
            return m_constraints;
        }

        public sealed override object Deserialize(object serializedValue) {
            if (serializedValue == null)
                return null;

            if (m_constraints.None())
                return serializedValue;

            return GetContract(serializedValue).Deserialize(serializedValue);
        }
        internal sealed override object SerializeImpl(object deserializedValue) {
            if (m_constraints.None())
                return deserializedValue;

            return GetContract(deserializedValue).Serialize(deserializedValue);
        }
        public sealed override XsContract GetContractOrNull(object instance) {
            return Assembly.GetContractOrNull(instance, Constraints());
        }
        public sealed override XsContract MakeConstrainedContract(IEnumerable<XsContract> constraints) {
            return Assembly.MakeConstrainedObject(constraints);
        }
        public sealed override XsContract ContstraintsCommonBaseContract {
            get {
                var result = Assembly.GetContract(typeof(object));
                if (Constraints().Any())
                    result = XsLoader.GetContractOrNull(Constraints().Select(o => o.MetadataType).GreatestCommonBaseType());
                return result;
            }
        }
        #endregion
    }
    #endregion

    #region Complex Contract                (Content, Complex, Group, Annotation)
    internal abstract class XsContentContract : XsContract {

        #region Private Data Members
        private XsContract m_baseContract;
        private IEnumerable<XsMember> m_sequenceMembers;
        private IEnumerable<XsOperation> m_operations;
        private IEnumerable<XsOperation> m_declaredOperations;
        private Dictionary<MethodBase, XsOperation> m_operationsByMethodBase;
        private Dictionary<string, IEnumerable<XsOperation>> m_operationsByName;
        private Dictionary<XName, IEnumerable<XsOperation>> m_operationsByXName;

        private Func<object> m_factory;
        private Func<long, object> m_factoryWithId;
        private bool m_mustDeriveByRestriction;
        private bool m_contentIsComplex;
        #endregion

        #region Constructor
        internal XsContentContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {

            m_baseContract = XsLoader.GetContract(metadataType.BaseType).MakeRequired(IsRequired);

            // Check that ComplexDataContracts have default constructor
            if (metadataType.GetDefaultCtor() == null)
                throw new ArgumentException();
            m_factory = metadataType.Activate;

            // Cook the factory
            var activate = metadataType.GetStatic<MethodInfo>("Activate", typeof(long));
            if (activate != null)
                m_factoryWithId = delegate(long id) { return activate.Invoke(null, new object[] { id }); };

            var attribute = metadataType.GetAttribute<XsContentAttribute>();
            m_mustDeriveByRestriction = attribute.MustDeriveByRestriction;

            if (attribute.IsRestriction != IsRestriction)
                throw new ArgumentException();

            if (m_baseContract.IsObject)
                m_contentIsComplex = Members().None(o => o.IsSimpleContent);
            else
                m_contentIsComplex = BaseContract.ToLinkList(o => o.BaseContract).None(o => o.IsSimple);
        }
        #endregion

        #region Public Members
        public sealed override bool CanBeEmpty {
            get { return Members().None(o => !o.IsAttribute && o.IsRequired); }
        }
        public sealed override XsContract BaseContract {
            get { return m_baseContract; }
        }
        public sealed override bool IsDeriveByRestriction {
            get { return m_mustDeriveByRestriction; }
        }
        public sealed override bool IsRestriction {
            get { return BaseContract.IsDeriveByRestriction; }
        }
        public sealed override Type SerializedType {
            get { return MetadataType; }
        }
        public sealed override bool ContentIsSimple { 
            get { return !ContentIsComplex; } 
        }
        public sealed override bool ContentIsComplex { 
            get { return m_contentIsComplex; } 
        }
        #endregion

        #region Public Members      (Members)
        public sealed override IEnumerable<XsMember> DeclaredMembers() {
            if (m_sequenceMembers == null) {

                // create XsMembers for all declared fields and properties attributed with XsMemberAttribute
                var memberTypes = MemberTypes.Property | MemberTypes.Field;
                var declaredMemberInfos =
                   (from memberInfo in MetadataType.GetInstanceDeclaredOnly<MemberInfo>(memberTypes)
                    where memberInfo.IsDefined<XsMemberAttribute>()
                    select memberInfo).ToArray();

                IEnumerable<XsMember> sequenceMembers = null;
                if (IsExtension) {
                    sequenceMembers = 
                       (from memberInfo in declaredMemberInfos
                        let member = new XsMember(this, memberInfo)
                        orderby member.Order, member.Name
                        select member).ToArray();

                } else {
                    var extensionBaseContract = BaseContract.ToLinkList(o => o.BaseContract).First(o => o.IsExtension);

                    // unrestrictable members are automatically inherited
                    var cannotRestrict =
                       (from inheritedMember in BaseContract.DeclaredMembers()
                        where !inheritedMember.CanRestrict
                        select new XsMember(this, inheritedMember)).ToArray();

                    // verify restrictions have a base element to restrict
                    var canRestrictByName = extensionBaseContract.Members().Where(o => o.CanRestrict).ToDictionary(o => o.Name);
                    var noBaseElement = declaredMemberInfos.Where(o => !canRestrictByName.ContainsKey(o.Name));
                    if (noBaseElement.Any())
                        throw new ArgumentException();

                    // verify MustRestrict members are restricted
                    var declaredMemberInfosByName = declaredMemberInfos.ToDictionary(o => o.Name);
                    var mustRestrictByName = extensionBaseContract.Members().Where(o => o.MustRestrict).ToArray();
                    if (mustRestrictByName.Any(o => !declaredMemberInfosByName.ContainsKey(o.Name)))
                        throw new ArgumentException();

                    // resolve the base member for the restriction
                    var declaredMembers =
                       (from o in declaredMemberInfos
                        let baseMember = extensionBaseContract.GetMember(o.Name)
                        select new XsMember(this, o, baseMember)).ToArray();

                    // the first extension base contract determines the order
                    sequenceMembers = 
                       (from o in declaredMembers.Union(cannotRestrict)
                        let baseMember = extensionBaseContract.GetMember(o.Name)
                        orderby baseMember.Order
                        select o).ToArray();
                }

                // check for duplicate names
                var duplicates = sequenceMembers.FlattenGroups().GroupBy(o => o.Name).Where(o => o.MoreThanOne());
                if (duplicates.Any())
                    throw new ArgumentException();

                m_sequenceMembers = sequenceMembers;
            }

            return m_sequenceMembers;
        }
        public sealed override IEnumerable<XsMember> Members() {
            var members = this.BaseContract
                .ToLinkList(o => o.BaseContract).Reverse()
                .Where(o => o.IsDeriveByExtension)                
                .Concat(this)
                .SelectMany(o => o.DeclaredMembers());
            return members;
        }
        #endregion

        #region Public Members      (Operations)
        public sealed override XsOperation GetOperation(MethodBase methodBase) {
            if (m_operationsByMethodBase == null)
                m_operationsByMethodBase = Operations().ToDictionary(o => (MethodBase)o.MethodInfo);

            XsOperation operation;
            m_operationsByMethodBase.TryGetValue(methodBase, out operation);
            return operation;
        }
        public sealed override IEnumerable<XsOperation> DeclaredOperations() {
            if (m_declaredOperations == null)
                m_declaredOperations =
                   (from o in MetadataType.GetDeclaredOnly<MethodInfo>()
                    where o.IsDefined<XsOperationAttribute>()
                    orderby o.Name
                    select new XsOperation(o)
                    ).ToArray();

            return m_declaredOperations;
        }
        public sealed override IEnumerable<XsOperation> Operations(XName name) {
            // create the cache
            if (m_operationsByXName == null) {
                m_operationsByXName =
                   (from o in Operations()
                    group o by o.FullName into o
                    select o)
                    .ToDictionary(
                        o => o.Key,
                        o => (IEnumerable<XsOperation>)o);
            }

            // if no name has no namespace then use the assembly in which the operation lives
            if (name.Namespace == XNamespace.None) {
                if (Assembly.ContractSchema == null)
                    return Enumerable.Empty<XsOperation>();
                name = Assembly.ContractSchema.Namespace + name.LocalName;
            }

            // hit the cache
            IEnumerable<XsOperation> cached;
            m_operationsByXName.TryGetValue(name, out cached);
            return cached ?? Enumerable.Empty<XsOperation>();
        }
        public sealed override IEnumerable<XsOperation> Operations(string name) {
            // create the cache
            if (m_operationsByName == null) {
                m_operationsByName = 
                   (from o in Operations()
                    group o by o.Name into o 
                    select o)
                    .ToDictionary(
                        o => o.Key, 
                        o => (IEnumerable<XsOperation>)o);
            }

            // hit the cache
            IEnumerable<XsOperation> cached;
            m_operationsByName.TryGetValue(name, out cached);
            return cached ?? Enumerable.Empty<XsOperation>();
        }
        public sealed override IEnumerable<XsOperation> Operations() {
            if (m_operations == null) {
                var operations = ((XsContract)this)
                    .ToLinkList(o => o.BaseContract)
                    .SelectMany(o => o.DeclaredOperations());

                m_operations = operations.Where(o => 
                    operations.None(x => 
                        x.MethodInfo.IsOverrideOf(o.MethodInfo))).ToArray();
            }
            return m_operations;
        }
        #endregion
    }
    internal sealed class XsComplexContract : XsContentContract {

        #region Private Data Members
        private Type m_deserializedType;
        #endregion

        #region Constructor
        internal XsComplexContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {

            m_deserializedType = metadataType;

            var attribute = metadataType.GetAttribute<XsComplexContractAttribute>();
            if (attribute.DeserializedType != null)
                m_deserializedType = attribute.DeserializedType;
        }
        #endregion

        #region Public Members
        public sealed override Type DeserializedType {
            get { return m_deserializedType; }
        }
        #endregion
    }
    internal sealed class XsGroupContract : XsContentContract {

        #region Constructor
        internal XsGroupContract(Type type, bool isRequired)
            : base(type, isRequired) {

            if (!type.IsValueType)
                throw new ArgumentException();
        }
        #endregion

        #region Public Members (Latebound)
        public sealed override object Deserialize(object serializedValue) {
            return base.Deserialize(serializedValue);
        }
        internal sealed override object SerializeImpl(object deserializedValue) {
            return base.SerializeImpl(deserializedValue);
        }
        #endregion
    }
    internal sealed class XsAnnotationContract : XsContentContract {

        #region Constructor
        internal XsAnnotationContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {
        }
        #endregion
    }
    #endregion

    #region Simple Contract                 (Simple, BasicSimple, AnySimple, String, Decimal, Boolean)
    internal abstract class XsSimpleContract : XsContract {

        #region Private Data Members
        private MethodInfo m_serializeXml;
        private bool m_serializeXmlCached;

        private MethodInfo m_deserializeXml;
        private bool m_deserializeXmlCached;
        #endregion

        #region Constructor
        internal XsSimpleContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {

            // regex
            var attribute = metadataType.GetAttribute<XsSimpleContractAttribute>();
        }
        #endregion

        #region Public Members
        public sealed override bool IsDeriveByRestriction {
            get { return true; }
        }
        public override void TestXmlConstraints(string source) {

            // nill
            if (string.Empty.Equals(source) && !CanBeEmpty)
                throw new ArgumentException("Location '{0}' cannot be empty."
                    .Substitute(this));

            // regex
            if (Regex != null && !Regex.IsMatch(source))
                throw new Exception("'{0}' does not match regex constraint '{1}' on contract '{2}'."
                    .Substitute(source, Regex, this));

            BaseContract.TestXmlConstraints(source);
        }
        #endregion

        #region Public Members (Latebound)
        public override object DeserializeXml(string serializedValue) {
            if (!m_deserializeXmlCached) {
                m_deserializeXml = MetadataType.GetStatic<MethodInfo>("DeserializeXml", typeof(string));
                m_deserializeXmlCached = true;
            }

            object deserializedValue;
            if (m_deserializeXml != null) {
                deserializedValue = m_deserializeXml.Invoke(null, new object[] { serializedValue });
            } else {
                deserializedValue = BaseContract.DeserializeXml(serializedValue);
            }

            return deserializedValue;
        }
        public override string SerializeXml(object deserializedValue) {
            if (deserializedValue == null)
                return null;

            if (!m_serializeXmlCached) {
                m_serializeXml = MetadataType.GetStatic<MethodInfo>("SerializeXml", SerializedType);
                m_serializeXmlCached = true;
            }

            object serializedValue;
            if (m_serializeXml == null)
                serializedValue = BaseContract.SerializeXml(deserializedValue);
            else
                serializedValue = m_serializeXml.Invoke(null, new object[] { deserializedValue });

            return (string)serializedValue;
        }
        #endregion
    }
    internal abstract class XsBasicSimpleContract : XsSimpleContract {

        #region Private Data Members
        private XsContract m_baseContract;
        private Type m_deserializedType;
        private Type m_serializedType;
        private Regex m_regex;
        private XsSchema m_schema;
        #endregion

        #region Constructor
        internal XsBasicSimpleContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {

            var attribute = metadataType.GetAttribute<XsSimpleContractAttribute>();
            m_serializedType = attribute.SerializedType;

            // baseContract
            if (metadataType.BaseType == typeof(object))
                m_baseContract = Assembly.GetContract(m_serializedType);
            else
                m_baseContract = XsLoader.GetContract(metadataType.BaseType);

            // deserializedType
            m_deserializedType = attribute.DeserializedType ?? BaseContract.DeserializedType;

            // regex
            if (attribute.Pattern != null)
                m_regex = new Regex(attribute.Pattern);

            // schema
            m_schema = Assembly.ContractSchema;
            if (attribute.IsAttributeSchemaOnly)
                m_schema = Assembly.AttributeSchema;
        }
        #endregion

        #region Public Members
        public sealed override XsContract BaseContract {
            get { return m_baseContract; }
        }
        public sealed override Type SerializedType {
            get { return m_serializedType; }
        }
        public sealed override Type DeserializedType {
            get { return m_deserializedType; }
        }
        public sealed override Regex Regex {
            get { return m_regex; }
        }
        public sealed override XsSchema Schema {
            get { return m_schema; }
        }
        #endregion
    }
    internal sealed class XsAnySimpleContract : XsBasicSimpleContract {

        #region Private Data Members
        private bool m_canBeEmpty;
        #endregion

        #region Constructor
        internal XsAnySimpleContract(Type metadataType, bool isRequired, bool? canBeEmpty)
            : base(metadataType, isRequired) {

            m_canBeEmpty = canBeEmpty ?? true;
        }
        #endregion

        #region Public Members
        public sealed override bool CanBeEmpty {
            get { return m_canBeEmpty; }
        }
        public sealed override object DeserializeXml(string serializedValue) {
            return serializedValue;
        }
        public sealed override string SerializeXml(object deserializedValue) {
            return (string)deserializedValue;
        }
        public sealed override object DeserializeCsv(string serializedValue) {
            return serializedValue;
        }
        public sealed override string SerializeCsv(object deserializedValue) {
            return (string)deserializedValue;
        }
        #endregion
    }
    internal sealed class XsStringContract : XsBasicSimpleContract {

        #region Private Data Members
        private bool m_canBeEmpty;
        private int? m_maxLength;
        private int? m_minLength;
        #endregion

        #region Constructor
        internal XsStringContract(Type metadataType, bool isRequired, bool? canBeEmpty)
            : base(metadataType, isRequired) {

            // canBeEmpty
            m_canBeEmpty = canBeEmpty ?? (Regex == null ? true : Regex.IsMatch(string.Empty));

            var attribute = metadataType.GetAttribute<XsStringContractAttribute>();
            if (attribute == null)
                throw new ArgumentException();

            // constraints
            m_maxLength = (int?)attribute.Length;
            m_minLength = (int?)attribute.Length;

            if (attribute.Length != null && (attribute.MinLength != null || attribute.MaxLength != null))
                throw new ArgumentException();
        }
        #endregion

        #region Public Members
        public sealed override void TestXmlConstraints(string value) {
            
            // test maxLength
            if (m_maxLength != null && value.Length > m_maxLength)
                throw new ArgumentException("Value '{0}' stored in location '{1}' is longer than {2}."
                    .Substitute(value, this, m_maxLength));

            // test minLength
            if (m_minLength != null && value.Length < m_minLength)
                throw new ArgumentException("Value '{0}' stored in location '{1}' is shorter than {2}."
                    .Substitute(value, this, m_minLength));

            base.TestXmlConstraints(value);
        }
        public sealed override bool CanBeEmpty { 
            get { return m_canBeEmpty; } 
        }

        public sealed override int? MaxLength { get { return m_maxLength; } }
        public sealed override int? MinLength { get { return m_minLength; } }
        #endregion
    }
    internal sealed class XsDecimalContract : XsBasicSimpleContract {

        #region Private Members
        private int? m_totalDigits;
        private int? m_fractionDigits;
        private long? m_maxInclusive;
        private long? m_maxExclusive;
        private long? m_minInclusive;
        private long? m_minExclusive;
        #endregion

        #region Constructor
        internal XsDecimalContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {

            var attribute = metadataType.GetAttribute<XsDecimalContractAttribute>();
            if (attribute == null)
                throw new ArgumentException();

            if (attribute.TotalDigits != null)
                m_totalDigits = Convert.ToInt32(attribute.TotalDigits);

            if (attribute.FractionDigits != null)
                m_fractionDigits = Convert.ToInt32(attribute.FractionDigits);

            if (attribute.MaxInclusive != null)
                m_maxInclusive = Convert.ToInt64(attribute.MaxInclusive);

            if (attribute.MaxExclusive != null)
                m_maxExclusive = Convert.ToInt64(attribute.MaxExclusive);

            if (attribute.MinInclusive != null)
                m_minInclusive = Convert.ToInt64(attribute.MinInclusive);

            if (attribute.MinExclusive != null)
                m_minExclusive = Convert.ToInt64(attribute.MinExclusive);
        }
        #endregion

        #region Public Members
        public sealed override void TestConstraints(object value) {
            var number = Convert.ToDecimal(value);

            if (MaxInclusive != null && number > MaxInclusive)
                throw new ArgumentException("'{0}' is greater than '{1}'.".Substitute(value, MaxInclusive));

            if (MaxExclusive != null && number >= MaxExclusive)
                throw new ArgumentException("'{0}' is greater than or equal to '{1}'.".Substitute(value, MaxExclusive));

            if (MinInclusive != null && number < MinInclusive)
                throw new ArgumentException("'{0}' is less than '{1}'.".Substitute(value, MinInclusive));

            if (MinExclusive != null && number <= MinExclusive)
                throw new ArgumentException("'{0}' is less than or equal to '{1}'.".Substitute(value, MinExclusive));

            base.TestConstraints(value);
        }
        public sealed override long? MaxInclusive { get { return m_maxInclusive; } }
        public sealed override long? MinInclusive { get { return m_minInclusive; } }
        public sealed override long? MaxExclusive { get { return m_maxExclusive; } }
        public sealed override long? MinExclusive { get { return m_minExclusive; } }
        public sealed override int? TotalDigits { get { return m_totalDigits; } }
        public sealed override int? FractionDigits { get { return m_fractionDigits; } }
        #endregion
    }
    internal sealed class XsBooleanContract : XsBasicSimpleContract {

        #region Constructor
        internal XsBooleanContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) { 
        
            var attribute = metadataType.GetAttribute<XsBooleanContractAttribute>();
            if (attribute == null)
                throw new ArgumentException();
        }
        #endregion
    }
    #endregion

    #region List Contract                   (List, Enum, Constants, Union)
    internal abstract class XsListContract : XsSimpleContract {

        #region Private Data Members
        private XsContract m_baseContract;
        private XsSchema m_schema;
        #endregion

        #region Constructor
        internal XsListContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {

            // deserializedType
            var attribute = metadataType.GetAttribute<XsListContractAttribute>();
            m_baseContract = Assembly.GetContract(attribute.BaseType);

            // schema
            m_schema = Assembly.ContractSchema;
            if (attribute.IsAttributeSchemaOnly)
                m_schema = Assembly.AttributeSchema;
        }
        #endregion

        #region Public Members
        public sealed override XsSchema Schema {
            get { return m_schema; }
        }
        public sealed override XsContract BaseContract {
            get { return m_baseContract; }
        }
        #endregion
    }
    internal sealed class XsEnumContract : XsListContract {

        #region Private Data Members
        private Type m_deserializedType;
        private bool m_canBeEmpty;
        private bool m_isFlags;
        private IEnumerable<XsEnum> m_enums;
        private IEnumerable<XsMask> m_masks;
        private EnumInfo m_serializedEnumInfo;
        private EnumInfo m_deserializedEnumInfo;
        #endregion

        #region Constructor
        internal XsEnumContract(Type metadataType, bool isRequired, bool? canBeEmpty)
            : base(metadataType, isRequired) {

            if (!SerializedType.IsEnum)
                throw new ArgumentException();
            m_serializedEnumInfo = EnumInfo.GetEnumInfo(SerializedType);

            m_isFlags = metadataType.IsDefined<FlagsAttribute>();

            var attribute = MetadataType.GetAttribute<XsEnumContractAttribute>();
            m_deserializedType = attribute.DeserializedType ?? MetadataType;

            m_enums = m_serializedEnumInfo.Values().Select(o => new XsEnum(this, o)).ToArray();
            m_masks = m_serializedEnumInfo.Masks().Select(o => new XsMask(this, o)).ToArray();

            if (DeserializedType.IsEnum)
                m_deserializedEnumInfo = EnumInfo.GetEnumInfo(DeserializedType);

            m_canBeEmpty = canBeEmpty ?? m_enums.Any(o => o.IsEmptyValue);
        }
        #endregion

        #region Public Members
        public sealed override Type DeserializedType {
            get { return m_deserializedType; }
        }
        public sealed override Type SerializedType {
            get { return MetadataType; }
        }
        public sealed override bool CanBeEmpty {
            get { return m_canBeEmpty; }
        }
        public sealed override bool IsFlags {
            get { return m_isFlags; }
        }
        public sealed override IEnumerable<XsMask> Masks() {
            return m_masks;
        }
        public sealed override IEnumerable<XsEnum> Enums() {
            return m_enums;
        }
        public sealed override IEnumerable<XsEnum> Enums(object serializedValue) {
            if (serializedValue == null)
                return Enumerable.Empty<XsEnum>();

            EnumInfo enumInfo;
            if (serializedValue.GetType() == m_serializedEnumInfo.Type)
                enumInfo = m_serializedEnumInfo;
            else if (serializedValue.GetType() == m_deserializedEnumInfo.Type)
                enumInfo = m_deserializedEnumInfo;
            else
                throw new InvalidOperationException();

            var enums =
                from o in m_serializedEnumInfo.Values(serializedValue)
                join x in Enums() on o equals x.SerializedEnumValue
                select x;
            return enums.ToArray();
        }
        public sealed override IEnumerable<XsEnum> CannonicalEnums(object value) {
            var values = Enums(value);
            values = values.Where(o => values.All(x => x == o || !o.EnumValue.IsSet(x.Value))).ToArray();
            return values;
        }
        public sealed override object ToObject(IEnumerable<XsEnum> flags) {
            return flags.Select(o => o.SerializedValue).ToEnum(SerializedType);
        }

        public sealed override object Deserialize(object serializedValue) {
            if (serializedValue == null)
                return null;

            var enums = Enums(serializedValue);

            if (enums.None())
                throw new ArgumentException(
                    "'0x{0:x}' is not a valid bit combination for enum '{1}'.".Substitute(serializedValue, this));

            if (enums.Any(o => o.IsEmptyValue) && !CanBeEmpty)
                throw new ArgumentException(
                    "Attempted to deserialize an empty values for type '{0}' which disallows empty values.".Substitute(this));

            var deserializedValues = enums.Select(o => o.DeserializedValue).ToArray();

            object deserializedValue = null;
            if (DeserializedType.IsEnum)
                deserializedValue = deserializedValues.ToEnum(DeserializedType);

            else
                deserializedValue = deserializedValues.Single();
            return deserializedValue;
        }
        internal sealed override object SerializeImpl(object deserializedValue) {
            var map =
               (from o in Enums()
                from x in o.DeserializedValueAliases().Union(o.DeserializedValue)
                select new {
                    SerializedValue = o.SerializedValue,
                    DeserializedValue = x
                }).ToArray();

            object result;
            if (DeserializedType.IsEnum) {
                var deserializedValues = m_deserializedEnumInfo.Values(deserializedValue);
                var serializedValues =
                   (from o in deserializedValues
                    join x in map on o.Value equals x.DeserializedValue
                    select x.SerializedValue).ToArray();
                result = serializedValues.ToEnum(SerializedType);

            } else {
                result = map.Single(o => object.Equals(o.DeserializedValue, deserializedValue)).SerializedValue;
            }
            return result;
        }

        public override object DeserializeXml(string xml) {
            if (xml == null)
                return null;

            // split enum values by white space
            var names = xml.StringSplit(' ', '\n', '\r', '\t').ToArray();

            // test for duplicates
            if (names.Duplicates().Any())
                throw new ArgumentException("The following enum values were duplicated: " +
                    names.Duplicates().StringJoin(", "));

            // list of enum values matching those passed in
            var enums =
                from o in names
                join e in Enums() on o equals e.SchemaName into e
                select new { Name = o, Enums = e };

            // test for bad values
            var badEnums = enums.Where(o => o.Enums.None()).ToArray();
            if (badEnums.Any())
                throw new ArgumentException("The following enum values are not recognized: " + 
                    badEnums.StringJoin(", ", o => o.Name));

            var values = enums.Select(o => o.Enums.Single().SerializedValue);

            // aggregate serializedValues if we dealing with flags
            if (IsFlags)
                return values.ToEnum(SerializedType);
            else if (values.MoreThanOne())
                throw new ArgumentException(xml, "Elements of type '" + Name + "' can have only one enum value.");
            else
                return values.Single();
        }
        public override string SerializeXml(object deserializedValue) {
            if (deserializedValue == null)
                return null;

            var result = CannonicalEnums(deserializedValue).StringJoin(" ", o => o.SchemaName);
            return result;
        }

        public override object DeserializeCsv(string csv) {
            return DeserializeXml(csv);
        }
        public override string SerializeCsv(object deserializedValue) {
            return SerializeXml(deserializedValue);
        }
        #endregion
    }
    internal sealed class XsConstantsContract : XsListContract {

        #region Private Data Members
        private XsContract m_baseContract;
        private Type m_serializedType;
        private Type m_deserializedType;

        private bool m_canBeEmpty;
        private IEnumerable<XsConstant> m_constants;

        private Dictionary<object, object> m_serializedValuesByDeserializedValues;
        private Dictionary<object, object> m_deserializedValuesBySerializedValues;
        #endregion

        #region Constructor
        internal XsConstantsContract(Type metadataType, bool isRequired, bool? canBeEmpty)
            : base(metadataType, isRequired) {

            if (!metadataType.IsStatic())
                throw new ArgumentException();

            var attribute = MetadataType.GetAttribute<XsConstantsContractAttribute>();
            m_serializedType = BaseContract.SerializedType;
            m_deserializedType = attribute.DeserializedType ?? BaseContract.DeserializedType;

            m_constants =
               (from o in MetadataType.GetStatic<FieldInfo>()
                where o.IsDefined<XsConstantAttribute>()
                select new XsConstant(this, o)).ToArray();

            if (IsAlias) {
                m_serializedValuesByDeserializedValues = Constants().ToDictionary(o => o.DeserializedValue, o => o.SerializedValue);
                m_deserializedValuesBySerializedValues = Constants().ToDictionary(o => o.SerializedValue, o => o.DeserializedValue);
            }
        }
        #endregion

        #region Public Members
        public sealed override Type SerializedType {
            get { return m_serializedType; }
        }
        public sealed override Type DeserializedType {
            get { return m_deserializedType; }
        }
        public sealed override bool CanBeEmpty {
            get { return m_canBeEmpty; }
        }

        public sealed override IEnumerable<XsConstant> Constants() {
            return m_constants;
        }

        public sealed override object Deserialize(object serializedValue) {
            if (m_deserializedValuesBySerializedValues == null)
                return base.Deserialize(serializedValue);

            object result;
            if (!m_deserializedValuesBySerializedValues.TryGetValue(serializedValue, out result))
                throw new ArgumentException("Could not deserialize '{0}' into a '{1}'.".Substitute(serializedValue, this));
            return result;
        }
        internal sealed override object SerializeImpl(object deserializedValue) {
            if (m_serializedValuesByDeserializedValues == null)
                return base.Serialize(deserializedValue);

            object result = m_deserializedValuesBySerializedValues[deserializedValue];
            return result;
        }
        #endregion
    }
    internal sealed class XsUnionContract : XsListContract {

        #region Private Data Members
        private Type m_deserializedType;
        private IEnumerable<XsContract> m_contracts;
        #endregion

        #region Constructor
        internal XsUnionContract(Type metadataType, bool isRequired)
            : base(metadataType, isRequired) {

            var attribute = metadataType.GetAttribute<XsUnionContractAttribute>();
            m_contracts = attribute.Types.Select(o => XsLoader.GetContract(o)).ToArray();

            if (m_contracts.Any(o => !o.IsEnum || o.IsFlags))
                throw new ArgumentException();

            if (Enums().Select(o => o.DeserializedValue).Duplicates().Any())
                throw new ArgumentException();

            if (m_contracts.Any(o => !o.IsDerivationOf(BaseContract)))
                throw new ArgumentException();

            m_deserializedType = attribute.DeserializedType ?? typeof(Enum);
        }
        #endregion

        #region Public Members
        public sealed override IEnumerable<XsContract> Lists() {
            return m_contracts;
        }
        public sealed override IEnumerable<XsEnum> Enums() {
            return m_contracts.SelectMany(o => o.Enums());
        }

        public sealed override Type DeserializedType {
            get { return m_deserializedType; }
        }
        public sealed override Type SerializedType {
            get { return typeof(Enum); }
        }
        public sealed override XsContract GetContractOrNull(object instance) {
            if (instance == null || !instance.GetType().IsEnum)
                return null;

            var enumValue = Enums().SingleOrDefault(o => 
                object.Equals(instance, o.SerializedValue));

            if (enumValue == null)
                return null;

            return enumValue.DeclaringContract;
        }

        public sealed override object Deserialize(object serializedValue) {
            var contract = GetContract(serializedValue);
            var result = contract.Deserialize(serializedValue);
            return result;
        }
        internal sealed override object SerializeImpl(object deserializedValue) {
            var enumValue = Enums().Single(o =>
                object.Equals(deserializedValue, o.DeserializedValue));
            return enumValue.DeclaringContract.Serialize(deserializedValue);
        }
        #endregion

        public override object DeserializeXml(string xml) {
            // list of enum values matching those passed in
            var enums = Enums()
                .Join(xml.StringSplit(' '),
                    o => o.SchemaName, /* == */ o => o,
                    (o, i) => o.SerializedValue);

            // aggregate serializedValues if we dealing with flags
            if (IsFlags)
                return enums.ToEnum(SerializedType);
            else if (enums.MoreThanOne())
                throw new ArgumentException(xml, "Elements of type '" + Name + "' can have only one enum value.");
            else
                return enums.Single();
        }
        public override string SerializeXml(object deserializedValue) {
            var result = CannonicalEnums(deserializedValue).StringJoin(" ", o => o.SchemaName);
            return result;
        }
    }
    #endregion

    #region Enumerations                    (Enum, Constant, Mask)
    public sealed class XsEnum : XsObject {

        #region Private Data Members
        private XsListContract m_declaringContract;
        private object m_serializedValue;
        private EnumValue m_clientEnumValue;
        private EnumValue m_enumValue;
        private bool m_isDefaultValue;

        private object m_deserializedValue;
        private string m_deserializedName;
        private IEnumerable<object> m_deserializedValueAliases;
        
        private XsMask m_mask;
        private IEnumerable<XsEnum> m_enums;
        #endregion

        #region Constructor
        internal XsEnum(XsListContract contract, EnumValue enumValue)
            : base(enumValue.FieldInfo) {

            m_declaringContract = contract;
            m_serializedValue = enumValue.FieldInfo.GetValue();
            m_enumValue = enumValue;
            m_isDefaultValue = SerializedValue.Equals(SerializedType.GetDefaultValue());

            var attribute = enumValue.FieldInfo.GetAttribute<XsEnumAttribute>() ?? new XsEnumAttribute();
            m_deserializedValue = attribute.DeserializedValue ?? SerializedValue;
            m_deserializedName = attribute.DeserializedName ?? Name;

            var aliases = attribute.Alias.ToSingletonOrToEnumerable();
            m_deserializedValueAliases = aliases.ToSingletonOrToEnumerable().ToArray();

            var clientEnum = enumValue.FieldInfo.GetAttribute<XsClientEnumAttribute>();
            if (clientEnum != null)
                m_clientEnumValue = EnumValue.GetEnumValue(clientEnum.DeserializedValue).Single();
        }
        #endregion

        #region Public Members
        public XsContract DeclaringContract {
            get { return m_declaringContract; }
        }
        public sealed override XsSchema Schema {
            get { return DeclaringContract.Schema; }
        }
        public Type SerializedType {
            get { return DeclaringContract.SerializedType; }
        }
        public object SerializedValue {
            get { return m_serializedValue; }
        }
        public EnumValue SerializedEnumValue {
            get { return m_enumValue; }
        }
        public bool IsEmptyValue {
            get { return Mask == null && IsDefaultValue; }
        }
        public bool IsDefaultValue {
            get { return m_isDefaultValue; }
        }

        public EnumValue EnumValue {
            get { return m_enumValue; } 
        }
        public object Value {
            get { return m_enumValue.Value; }
        }
        public EnumValue ClientEnumValue {
            get { return m_clientEnumValue; } 
        }
        public object ClientValue {
            get { return m_clientEnumValue.Value; }
        }
        public bool IsFlags {
            get {
                if (Mask != null)
                    return false;
                return DeclaringContract.IsFlags;
            }
        }
        public IEnumerable<XsEnum> Enums() {
            if (m_enums == null) {
                var enums =
                    from o in m_enumValue.Values()
                    join x in DeclaringContract.Enums() on o equals x.SerializedEnumValue
                    select x;
                Interlocked.CompareExchange(ref m_enums, enums.ToArray(), null);
            }
            return m_enums;
        }
        public XsMask Mask {
            get {
                if (m_mask == null && SerializedEnumValue.Mask != null) {
                    var mask = DeclaringContract.Masks().Single(o => o.SerializedMask == SerializedEnumValue.Mask);
                    Interlocked.CompareExchange(ref m_mask, mask, null);
                }
                return m_mask;
            }
        }

        public Type DeserializedType {
            get { return DeclaringContract.DeserializedType; }
        }
        public object DeserializedValue {
            get { return m_deserializedValue; }
        }
        public string DeserializedName {
            get { return m_deserializedName; }
        }
        public IEnumerable<object> DeserializedValueAliases() {
            return m_deserializedValueAliases;
        }
        #endregion

        #region Object Overrides
        public override string ToString() {
            var result = SerializedEnumValue.ToString();
            if (DeclaringContract.IsAlias) {
                result += " (";
                if (DeserializedType.IsEnum)
                    result += EnumInfo.ToString((Enum)DeserializedValue);
                else
                    result += DeserializedValue;
                result += ")";
            }
            return result;
        }
        #endregion
    }
    public sealed class XsConstant : XsObject {

        #region Private Members
        private XsContract m_declaringContract;
        private object m_serializedValue;
        private object m_deserializedValue;
        private string m_metadataName;
        #endregion

        #region Constructor
        internal XsConstant(XsListContract contract, MemberInfo memberInfo)
            : base(memberInfo) {

            m_declaringContract = contract;
            m_serializedValue = memberInfo.GetValue();
            m_metadataName = memberInfo.Name;

            var attribute = memberInfo.GetAttribute<XsConstantAttribute>();
            m_deserializedValue = attribute.DeserializedValue ?? m_serializedValue;
        }
        #endregion

        #region Public Members
        public XsContract DeclaringContract {
            get { return m_declaringContract; }
        }
        public sealed override XsSchema Schema {
            get { return DeclaringContract.Schema; }
        }
        public string MetadataName {
            get { return m_metadataName; }
        }
        public Type SerializedType {
            get { return DeclaringContract.SerializedType; }
        }
        public object SerializedValue {
            get { return m_serializedValue; }
        }

        public Type DeserializedType {
            get { return DeclaringContract.DeserializedType; }
        }
        public object DeserializedValue {
            get { return m_deserializedValue; }
        }
        #endregion

        #region Object Overrides
        public override string ToString() {
            return SerializedValue.ToString();
        }
        #endregion
    }
    public sealed class XsMask : XsObject {

        #region Private Data Members
        private XsListContract m_declaringContract;
        private IEnumerable<XsEnum> m_enums;

        private MaskValue m_serializedMask;
        private MaskValue m_deserializedMask;
        #endregion

        #region Constructor
        internal XsMask(XsListContract contract, MaskValue serializedMask)
            : base(serializedMask.FieldInfo) {

            m_declaringContract = contract;
            m_serializedMask = serializedMask;
        }
        #endregion

        #region Public Members
        public XsContract DeclaringContract {
            get { return m_declaringContract; }
        }
        public sealed override XsSchema Schema {
            get { return DeclaringContract.Schema; }
        }
        public string Name {
            get { return m_serializedMask.Name; }
        }

        public MaskValue SerializedMask {
            get { return m_serializedMask; }
        }
        public object SerializedValue {
            get { return m_serializedMask.Value; }
        }

        public IEnumerable<XsEnum> Enums() {
            if (m_enums == null) {
                var enums =
                    from o in SerializedMask.Values()
                    join x in DeclaringContract.Enums() on o equals x.SerializedEnumValue
                    select x;
                Interlocked.CompareExchange(ref m_enums, enums.ToArray(), null);

                var enumInfo = EnumInfo.GetEnumInfo(DeclaringContract.DeserializedType);
                if (enums.Select(o => enumInfo.GetValue(o.DeserializedValue)).GroupBy(o => o.Mask).MoreThanOne())
                    throw new ArgumentException();
            }
            return m_enums;
        }
        #endregion

        #region Object Overrides
        public override string ToString() {
            return Name;
        }
        #endregion
    }
    #endregion

    #region Locations                       (Location, Operation, Parameter, Member)
    public sealed class XsOperation : XsObject {

        #region Private Data Members
        // identity
        private MethodInfo m_methodInfo;
        private XsContract m_declaringContract;

        // parameters
        private XsParameter m_returnParameter;
        private IEnumerable<XsParameter> m_parameters;
        private bool m_isParams;
        private bool m_isOverride;
        #endregion

        #region Constructor
        internal XsOperation(MethodInfo methodInfo)
            : base(methodInfo) {
            m_methodInfo = methodInfo;
            m_declaringContract = XsLoader.GetContractOrNull(methodInfo.DeclaringType);

            if (methodInfo.ReturnType != typeof(void))
                m_returnParameter = new XsParameter(this, methodInfo.ReturnParameter);

            m_parameters = 
               (from o in methodInfo.GetParameters()
                where !o.IsDefined<XsRuntimeParameterAttribute>()
                select new XsParameter(this, o))
                .ToArray();

            if (m_parameters.Any() && m_parameters.Last().IsParams)
                m_isParams = true;

            m_isOverride = m_methodInfo.IsVirtual && m_methodInfo.GetOverrides().Any(o => o.IsDefined<XsOperationAttribute>());
        }
        #endregion

        #region Public Members
        // identity
        public MethodInfo MethodInfo { get { return m_methodInfo; } }
        public XsContract DeclaringContract { get { return m_declaringContract; } }
        public sealed override XsSchema Schema {
            get { return DeclaringContract.Schema; }
        }

        // parameters
        public XsParameter ReturnParameter { get { return m_returnParameter; } }
        public IEnumerable<XsParameter> Parameters() { return m_parameters; }

        // metadata
        public bool IsStatic { get { return m_methodInfo.IsStatic; } }
        public bool IsParams { get { return m_isParams; } }
        public bool IsVirtual { get { return m_methodInfo.IsVirtual; } }
        public bool IsOverride { get { return m_isOverride; } }

        // dynamic operations
        public object Invoke(object @this, params object[] arguments) {
            return m_methodInfo.Invoke(@this, arguments);
        }
        #endregion

        #region Object Overrides
        public override string ToString() {
            return "{0}.{1}({2})".Substitute(
                DeclaringContract.ToStringInternal(),
                Name ?? "[anonymous]",
                m_parameters.StringJoin(", ", o => o.Contract.ToStringInternal()));
        }
        #endregion
    }
    public abstract class XsLocation : XsObject {

        #region Private Data Members
        private Type m_propertyOrFieldType;
        private bool m_isAbstract;
        private string m_metadataName;
        private bool m_isRequired;
        private int m_order;

        private XsContract m_contract;

        private object m_defaultValue;
        private bool m_provideDefault;
        private object m_emptyValue;

        private bool m_ignoreXmlRoot;
        private bool m_indentText;

        private bool m_useCDataSection;
        private bool m_useTypedObject;  // (e.g. Enums.UnitedStatesStates and Enums.UnitedKingdomCounties)      
        #endregion

        #region Constructor
        internal XsLocation(MemberInfo memberInfo)
            : this(memberInfo, null) { }
        internal XsLocation(MemberInfo memberInfo, XsMember baseMember)
            : base(memberInfo) {
            
            var isAnnotationContract = memberInfo.DeclaringType.IsDefined<XsAnnotationContractAttribute>();

            // properties must be read\write (except for Annotation properties)
            if (!isAnnotationContract && !memberInfo.CanReadWrite())
                throw new ArgumentException();

            // check that all ContractMembers are instance members
            if (memberInfo.IsStatic())
                throw new ArgumentException();

            m_metadataName = memberInfo.Name;
            m_propertyOrFieldType = memberInfo.GetPropertyOrFieldType();

            var attribute = memberInfo.GetAttribute<XsMemberAttribute>();
            if (isAnnotationContract) {
                attribute.CanBeEmpty = false;
                if (!memberInfo.CanWrite())
                    attribute.IsRequired = true;
            }

            m_order = attribute.Order;
            if (baseMember != null)
                m_order = baseMember.Order;

            Initialize(memberInfo, attribute, memberInfo, attribute.IsRequired);
        }
        internal XsLocation(XsContract contract)
            : base(contract.Assembly) {

            // "this" argument
            m_contract = contract.MakeRequired();
            m_propertyOrFieldType = contract.DeserializedType;
            m_order = 0;
            m_isRequired = true;
        }
        internal XsLocation(ParameterInfo parameterInfo)
            : base(parameterInfo) {
            var isAnnotationContract = parameterInfo.Member.DeclaringType.IsDefined<XsAnnotationContractAttribute>();

            m_metadataName = parameterInfo.IsReturnParameter() ? null : parameterInfo.Name;
            m_propertyOrFieldType = parameterInfo.ParameterType;
            m_order = parameterInfo.Position;

            var attribute = parameterInfo.GetAttribute<XsParameterAttribute>() ?? new XsParameterAttribute();
            var isRequired = !attribute.IsOptional || parameterInfo.IsReturnParameter();

            Initialize(parameterInfo, attribute, parameterInfo.Member, isRequired);

            if (m_contract.IsGroup)
                throw new ArgumentException();
        }
        #endregion

        #region Private Members
        private XsContract GetContract(Type type, bool? canBeEmpty) {
            var result = Assembly.GetContract(type);
            if (canBeEmpty != null)
                result = result.MakeCanBeEmpty((bool)canBeEmpty);
            return result;
        }
        private void Initialize(ICustomAttributeProvider cap, XsLocationAttribute attribute, MemberInfo memberInfo, bool isRequired) {

            m_isAbstract = memberInfo.IsAbstract() || memberInfo.IsOpenVirtual();

            // override name
            if (attribute.Name != null)
                m_metadataName = attribute.Name;

            InitializeContract(attribute.Contract, attribute.CanBeEmpty, isRequired);
            InitializeText(attribute.IndentText, attribute.IgnoreXmlRoot);
            InitializeUseCDataSection(attribute.UseCDataSection);
            InitializeEmptyValue();
            InitializeDefault(isRequired, attribute.ProvideDefault);
            InitializeUseTypedObject(attribute.UseTypedObject);

            // an abstract ContractMember may not be constrainted sufficiently to be assigned to the location
            // only in derived Contracts are there sufficient constraints to ensure assignablity.
            if (!m_isAbstract && !IsAssignableFrom(m_contract))
                throw new ArgumentException();
        }
        private void InitializeContract(object attributeContractObject, object canBeEmptyObject, bool isRequired) {
            XsContract contract = null;
            var attributeContract = attributeContractObject as Type;
            var attributeContracts = attributeContractObject as Type[];

            if (canBeEmptyObject != null && canBeEmptyObject.GetType() != typeof(bool))
                throw new ArgumentException();
            var canBeEmpty = (bool?)canBeEmptyObject;
            
            if (!m_propertyOrFieldType.IsEnumerable()) {

                if (attributeContract != null) {
                    contract = GetContract(attributeContract, canBeEmpty);

                } else if (attributeContracts != null) {
                    if (canBeEmpty == true)
                        throw new ArgumentException();

                    var constraints = attributeContracts.Select(o => Assembly.GetContract(o)).ToArray();
                    contract = Assembly.ObjectContract.MakeConstrainedContract(constraints);

                } else {
                    contract = GetContract(m_propertyOrFieldType, canBeEmpty);
                }

            } else {

                if (attributeContract != null) {
                    contract = Assembly.EnumerationContract.MakeConstrainedContract(Assembly.GetContract(attributeContract));

                } else if (attributeContracts != null) {
                    var constraints = attributeContracts.Select(o => Assembly.GetContract(o));
                    contract = Assembly.EnumerationContract.MakeConstrainedContract(constraints);

                } else {
                    contract = Assembly.GetContract(m_propertyOrFieldType);
                }
            }

            if (contract == null)
                throw new ArgumentException();

            if (canBeEmpty == true)
                contract = contract.MakeCanBeEmpty();
            else if (canBeEmpty == false)
                contract = contract.MakeCannotBeEmpty();

            if (attributeContractObject == null && 
                contract.MetadataType != m_propertyOrFieldType.UnNullify() && 
                !contract.IsMetadataAlias)
                throw new ArgumentException("Must explicitly declare a contract for a location of type " + m_propertyOrFieldType.ToCSharpToString() + ".");

            m_contract = contract.MakeRequired(isRequired);
        }
        private void InitializeEmptyValue() {
            if (m_contract.IsEnumeration) {
                m_emptyValue = m_contract.ElementContract.DeserializedType.ActivateEmpty();

            } else if (m_contract.IsString) {
                m_emptyValue = string.Empty;

            } else if (m_contract.IsEnum) {
                var defaultValue = m_contract.SerializedType.GetDefaultValue();
                var enums = m_contract.Enums(defaultValue);
                if (enums.Any())
                    m_emptyValue = defaultValue;
            }
        }
        private void InitializeDefault(bool isRequired, object defaultValue) {
            m_isRequired = isRequired;

            // verify attributes defaults are interesting
            if (defaultValue == null)
                return;

            m_provideDefault = true;

            // enumerations => { }
            if (m_contract.IsEnumeration) {
                if (!defaultValue.Equals(true))
                    throw new ArgumentException();
                m_defaultValue = m_emptyValue;

            // string => "" or a user provided string
            } else if (m_contract.IsString) {
                if (defaultValue.Equals(true))
                    m_defaultValue = m_emptyValue;
                m_defaultValue = defaultValue;

            // enum => default(enum)
            } else if (m_contract.IsEnum) {
                if (defaultValue.Equals(true)) {
                    if (m_emptyValue == null)
                        throw new ArgumentException();
                    m_defaultValue = m_emptyValue;
                }
                m_defaultValue = defaultValue;
                
            // use default if we can assign it to the location
            } else {
                m_defaultValue = defaultValue;
            }

            if (!m_contract.SerializedType.IsAssignableFrom(m_defaultValue))
                throw new ArgumentException();
        }
        private void InitializeText(bool indentText, bool ignoreXmlRoot) {
            m_indentText = indentText;
            if (m_indentText && !m_contract.IsXml && !m_contract.IsString)
                throw new ArgumentException();

            m_ignoreXmlRoot = ignoreXmlRoot;
            if (ignoreXmlRoot && !m_contract.IsXml)
                throw new ArgumentException();
        }
        private void InitializeUseCDataSection(bool useCDataSection) {
            m_useCDataSection = useCDataSection;

            if (m_useCDataSection && !m_contract.IsString)
                throw new ArgumentException();
        }
        private void InitializeUseTypedObject(bool useTypedObject) {

            if (!useTypedObject)
                return;

            // see if we can map from the clr type back to a Contract un-ambiguously
            var ambiguousContract = m_contract.Constraints().GroupBy(o => o.DeserializedType).Where(o => o.Count() > 1).ToArray();

            // if it's not ambiguous then why use a TypedObject?
            if (ambiguousContract.None())
                throw new ArgumentException();

            // even if it is ambiguous the clr type may be able to discriminate itself and allow
            // a mapping back to the Contract somehow. (e.g. State has a CountryId property)
            m_useTypedObject = true;
        }
        private bool IsAssignableFrom(XsContract contract) {

            if (contract == null)
                return false;

            if (m_propertyOrFieldType.IsEnumerable()) {
                var locationElementType = m_propertyOrFieldType.GetEnumerationElementType();
                var elementContract = contract.ElementContract;
                if (elementContract == null)
                    return false;

                var elementType = elementContract.DeserializedType.UnNullify();
                return locationElementType.IsAssignableFrom(elementType);
            }

            if (contract.IsObject)
                return contract.Constraints().All(o => IsAssignableFrom(o));

            //return m_deserializedType.IsAssignableFrom(contract.DeserializedType.UnNullify());
            return true;
        }
        #endregion

        #region Public Members
        public Type PropertyOrFieldType { get { return m_propertyOrFieldType; } }
        public XsContract Contract { get { return m_contract; } }
        public bool IsAbstract { get { return m_isAbstract; } }
        public int Order { get { return m_order; } }

        public bool IsRequired { get { return m_isRequired; } }
        public bool IsOptional { get { return !IsRequired; } }
        public bool ProvideDefault { get { return m_provideDefault; } }
        public object Default { get { return m_defaultValue; } }
        public object EmptyValue { get { return m_emptyValue; } }

        public bool IgnoreXmlRoot { get { return m_ignoreXmlRoot; } }
        public bool IndentText { get { return m_indentText; } }

        public bool TypedObjectResult { get { return m_useTypedObject; } }
        public bool UseCDataSection { get { return m_useCDataSection; } }
        #endregion
    }
    public sealed class XsParameter : XsLocation {

        #region Private Data Members
        private bool m_isReturnParameter;
        private XsOperation m_operation;
        private bool m_isParams;
        #endregion

        #region Constructor
        internal XsParameter(XsOperation operation, XsContract contract)
            : base(contract) {
            m_operation = operation;
        }
        internal XsParameter(XsOperation operation, ParameterInfo parameterInfo)
            : base(parameterInfo) {

            m_operation = operation;
            m_isReturnParameter = parameterInfo.Position < 0;
            m_isParams = parameterInfo.IsDefined<ParamArrayAttribute>();
        }
        #endregion

        #region Public Members
        public XsOperation Operation {
            get { return m_operation; }
        }
        public sealed override XsSchema Schema {
            get { return Operation.Schema; }
        }
        public bool IsReturnParameter {
            get { return m_isReturnParameter; }
        }
        public bool IsParams {
            get { return m_isParams; }
        }
        #endregion

        #region Object Overrides
        public override string ToString() {
            if (IsReturnParameter)
                return "[return] ({0})".Substitute(Contract);
            return "{0} ({1})".Substitute(Name ?? "this", Contract);
        }
        #endregion
    }
    public sealed class XsMember : XsLocation {

        #region Private Data Members
        private XsContract m_declaringContract;
        private bool? m_isChoice;               // true if this ContractMember has the same order as any other
        private bool m_isXmlAttribute;          // emit as an XAttribute instead of XElement
        private bool m_deferDeserializaiton;    // can only be applied to enumerations
        private bool m_isActivationParameter;

        private Action<object, object> m_setValue;
        private Func<object, object> m_getValue;
        private XsMember m_baseMember;
        private bool m_canRestrict;
        private bool m_mustRestrict;
        private bool m_isSimpleContent;
        #endregion

        #region Constructor
        internal XsMember(XsContract declaringContract, XsMember baseMember)
            : this(declaringContract, baseMember.MemberInfo, baseMember) {
        }
        internal XsMember(XsContract declaringContract, MemberInfo memberInfo)
            : this(declaringContract, memberInfo, null) {
        }
        internal XsMember(XsContract declaringContract, MemberInfo memberInfo, XsMember baseMember)
            : base(memberInfo, baseMember) {

            m_baseMember = baseMember;

            // identity
            m_declaringContract = declaringContract;

            var attribute = memberInfo.GetAttribute<XsMemberAttribute>();

            m_isActivationParameter = attribute.IsActivationParameter;
            m_isSimpleContent = attribute.IsSimpleContent;
            m_isXmlAttribute = attribute.IsAttribute;
            if (m_isXmlAttribute && !Contract.IsSimple)
                throw new ArgumentException();

            m_deferDeserializaiton = attribute.DeferDeserialization;
            if (m_deferDeserializaiton && !Contract.IsEnumeration)
                throw new ArgumentException();

            m_setValue = memberInfo.ToSetValueDelegate();
            m_getValue = memberInfo.ToGetValueDelegate();

            if (m_declaringContract.IsDeriveByRestriction) {
                m_canRestrict = attribute.CanRestrict || attribute.MustRestrict;
                m_mustRestrict = attribute.MustRestrict;
            } else {
                if (attribute.CanRestrict)
                    throw new ArgumentException();
            }

            // simple content must not have an order
            if (m_isSimpleContent != (attribute.Order == 0) && 
                !declaringContract.IsAnnotation && !declaringContract.IsRestriction)
                throw new ArgumentException();

            if (m_isSimpleContent && !Contract.IsSimple)
                throw new ArgumentException();
        }
        #endregion

        #region Public Members
        public XsMember BaseMember { get { return m_baseMember; } }
        public bool IsRestriction { get { return DeclaringContract.IsRestriction; } }
        public bool CanRestrict { get { return m_canRestrict; } }
        public bool MustRestrict { get { return m_mustRestrict; } }
        public bool IsActivationParameter { get { return m_isActivationParameter; } }
        public XsContract GetContractOrNull(object value) {
            if (Contract.IsObject)
                return Assembly.GetContractOrNull(value, Contract.Constraints());

            return Contract.GetContractOrNull(value);
        }
        public XsContract GetContract(object value) {
            var result = GetContractOrNull(value);
            if (result == null)
                throw new ArgumentException();
            return result;
        }

        // declaring type
        public XsContract DeclaringContract { get { return m_declaringContract; } }
        public sealed override XsSchema Schema {
            get { return DeclaringContract.Schema; }
        }

        // ContractMember metadata (xml)
        public bool IsChoice { 
            get {
                if (m_isChoice == null)
                    m_isChoice = DeclaringContract.DeclaredMembers().Any(o => o != this && o.Order == Order);
                return (bool)m_isChoice; 
            } 
        }
        public bool IsAttribute { get { return m_isXmlAttribute; } }
        public bool IsElement { get { return !m_isXmlAttribute; } }
        public bool IsSimpleContent { get { return m_isSimpleContent; } }

        // ContractMember metadata (defer)
        public bool DeferDeserialization { get { return m_deferDeserializaiton; } }

        // latebound operations
        public object GetValue(object instance) {
            return m_getValue(instance);
        }
        public void SetValue(object instance, object value) {
            m_setValue(instance, value);
        }
        #endregion

        #region Object Overrides
        public override string ToString() {
            return "{0}.{1} {{{2}}}".Substitute(DeclaringContract.Name, Name ?? "[anonymous]", Contract);
        }
        #endregion
    }
    #endregion
}
